diff --git a/InvenTree/InvenTree/api_tester.py b/InvenTree/InvenTree/api_tester.py index a803e6797f..e2bdae1d8f 100644 --- a/InvenTree/InvenTree/api_tester.py +++ b/InvenTree/InvenTree/api_tester.py @@ -18,6 +18,7 @@ class InvenTreeAPITestCase(APITestCase): email = 'test@testing.com' superuser = False + is_staff = True auto_login = True # Set list of roles automatically associated with the user @@ -40,8 +41,12 @@ class InvenTreeAPITestCase(APITestCase): if self.superuser: self.user.is_superuser = True - self.user.save() + if self.is_staff: + self.user.is_staff = True + + self.user.save() + for role in self.roles: self.assignRole(role) @@ -73,6 +78,22 @@ class InvenTreeAPITestCase(APITestCase): ruleset.save() break + def getActions(self, url): + """ + Return a dict of the 'actions' available at a given endpoint. + Makes use of the HTTP 'OPTIONS' method to request this. + """ + + response = self.client.options(url) + self.assertEqual(response.status_code, 200) + + actions = response.data.get('actions', None) + + if not actions: + actions = {} + + return actions + def get(self, url, data={}, expected_code=200): """ Issue a GET request diff --git a/InvenTree/InvenTree/apps.py b/InvenTree/InvenTree/apps.py index aeddb714a0..feb46ee667 100644 --- a/InvenTree/InvenTree/apps.py +++ b/InvenTree/InvenTree/apps.py @@ -4,7 +4,6 @@ import logging from django.apps import AppConfig from django.core.exceptions import AppRegistryNotReady -from django.conf import settings from InvenTree.ready import isInTestMode, canAppAccessDatabase import InvenTree.tasks @@ -66,10 +65,11 @@ class InvenTreeConfig(AppConfig): from djmoney.contrib.exchange.models import ExchangeBackend from datetime import datetime, timedelta from InvenTree.tasks import update_exchange_rates + from common.settings import currency_code_default except AppRegistryNotReady: pass - base_currency = settings.BASE_CURRENCY + base_currency = currency_code_default() update = False diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index 0695e69f48..c75a827cc7 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,4 +1,4 @@ -from django.conf import settings as inventree_settings +from common.settings import currency_code_default, currency_codes from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend @@ -22,8 +22,8 @@ class InvenTreeExchange(SimpleExchangeBackend): return { } - def update_rates(self, base_currency=inventree_settings.BASE_CURRENCY): + def update_rates(self, base_currency=currency_code_default()): - symbols = ','.join(inventree_settings.CURRENCIES) + symbols = ','.join(currency_codes()) super().update_rates(base=base_currency, symbols=symbols) diff --git a/InvenTree/InvenTree/fields.py b/InvenTree/InvenTree/fields.py index c496c1bb22..462d2b0e0e 100644 --- a/InvenTree/InvenTree/fields.py +++ b/InvenTree/InvenTree/fields.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import sys from .validators import allowable_url_schemes @@ -14,7 +15,12 @@ from django import forms from decimal import Decimal +from djmoney.models.fields import MoneyField as ModelMoneyField +from djmoney.forms.fields import MoneyField +from djmoney.models.validators import MinMoneyValidator + import InvenTree.helpers +import common.settings class InvenTreeURLFormField(FormURLField): @@ -34,6 +40,55 @@ class InvenTreeURLField(models.URLField): }) +def money_kwargs(): + """ returns the database settings for MoneyFields """ + kwargs = {} + kwargs['currency_choices'] = common.settings.currency_code_mappings() + kwargs['default_currency'] = common.settings.currency_code_default + return kwargs + + +class InvenTreeModelMoneyField(ModelMoneyField): + """ + Custom MoneyField for clean migrations while using dynamic currency settings + """ + + def __init__(self, **kwargs): + # detect if creating migration + if 'makemigrations' in sys.argv: + # remove currency information for a clean migration + kwargs['default_currency'] = '' + kwargs['currency_choices'] = [] + else: + # set defaults + kwargs.update(money_kwargs()) + + # Set a minimum value validator + validators = kwargs.get('validators', []) + + if len(validators) == 0: + validators.append( + MinMoneyValidator(0), + ) + + kwargs['validators'] = validators + + super().__init__(**kwargs) + + def formfield(self, **kwargs): + """ override form class to use own function """ + kwargs['form_class'] = InvenTreeMoneyField + return super().formfield(**kwargs) + + +class InvenTreeMoneyField(MoneyField): + """ custom MoneyField for clean migrations while using dynamic currency settings """ + def __init__(self, *args, **kwargs): + # override initial values with the real info from database + kwargs.update(money_kwargs()) + super().__init__(*args, **kwargs) + + class DatePickerFormField(forms.DateField): """ Custom date-picker field diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 9d00697230..330bd2bb68 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -21,6 +21,9 @@ import InvenTree.version from common.models import InvenTreeSetting from .settings import MEDIA_URL, STATIC_URL +from common.settings import currency_code_default + +from djmoney.money import Money def getSetting(key, backup_value=None): @@ -247,6 +250,22 @@ def decimal2string(d): return s.rstrip("0").rstrip(".") +def decimal2money(d, currency=None): + """ + Format a Decimal number as Money + + Args: + d: A python Decimal object + currency: Currency of the input amount, defaults to default currency in settings + + Returns: + A Money object from the input(s) + """ + if not currency: + currency = currency_code_default() + return Money(d, currency) + + def WrapWithQuotes(text, quote='"'): """ Wrap the supplied text with quotes diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py new file mode 100644 index 0000000000..c22b39dc43 --- /dev/null +++ b/InvenTree/InvenTree/metadata.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals + +import logging + +from rest_framework import serializers +from rest_framework.metadata import SimpleMetadata +from rest_framework.utils import model_meta +from rest_framework.fields import empty + +import users.models + + +logger = logging.getLogger('inventree') + + +class InvenTreeMetadata(SimpleMetadata): + """ + Custom metadata class for the DRF API. + + This custom metadata class imits the available "actions", + based on the user's role permissions. + + Thus when a client send an OPTIONS request to an API endpoint, + it will only receive a list of actions which it is allowed to perform! + + Additionally, we include some extra information about database models, + so we can perform lookup for ForeignKey related fields. + + """ + + def determine_metadata(self, request, view): + + metadata = super().determine_metadata(request, view) + + user = request.user + + if user is None: + # No actions for you! + metadata['actions'] = {} + return metadata + + try: + # Extract the model name associated with the view + self.model = view.serializer_class.Meta.model + + # Construct the 'table name' from the model + app_label = self.model._meta.app_label + tbl_label = self.model._meta.model_name + + metadata['model'] = tbl_label + + table = f"{app_label}_{tbl_label}" + + actions = metadata.get('actions', None) + + if actions is not None: + + check = users.models.RuleSet.check_table_permission + + # Map the request method to a permission type + rolemap = { + 'POST': 'add', + 'PUT': 'change', + 'PATCH': 'change', + 'DELETE': 'delete', + } + + # Remove any HTTP methods that the user does not have permission for + for method, permission in rolemap.items(): + if method in actions and not check(user, table, permission): + del actions[method] + + # Add a 'DELETE' action if we are allowed to delete + if 'DELETE' in view.allowed_methods and check(user, table, 'delete'): + actions['DELETE'] = True + + # Add a 'VIEW' action if we are allowed to view + if 'GET' in view.allowed_methods and check(user, table, 'view'): + actions['GET'] = True + + except AttributeError: + # We will assume that if the serializer class does *not* have a Meta + # then we don't need a permission + pass + + return metadata + + def get_serializer_info(self, serializer): + """ + Override get_serializer_info so that we can add 'default' values + to any fields whose Meta.model specifies a default value + """ + + serializer_info = super().get_serializer_info(serializer) + + try: + ModelClass = serializer.Meta.model + + model_fields = model_meta.get_field_info(ModelClass) + + # Iterate through simple fields + for name, field in model_fields.fields.items(): + + if field.has_default() and name in serializer_info.keys(): + + default = field.default + + if callable(default): + try: + default = default() + except: + continue + + serializer_info[name]['default'] = default + + # Iterate through relations + for name, relation in model_fields.relations.items(): + + if name not in serializer_info.keys(): + # Skip relation not defined in serializer + continue + + if relation.reverse: + # Ignore reverse relations + continue + + # Extract and provide the "limit_choices_to" filters + # This is used to automatically filter AJAX requests + serializer_info[name]['filters'] = relation.model_field.get_limit_choices_to() + + if 'help_text' not in serializer_info[name] and hasattr(relation.model_field, 'help_text'): + serializer_info[name]['help_text'] = relation.model_field.help_text + + except AttributeError: + pass + + return serializer_info + + def get_field_info(self, field): + """ + Given an instance of a serializer field, return a dictionary + of metadata about it. + + We take the regular DRF metadata and add our own unique flavor + """ + + # Run super method first + field_info = super().get_field_info(field) + + # If a default value is specified for the serializer field, add it! + if 'default' not in field_info and not field.default == empty: + field_info['default'] = field.get_default() + + # Force non-nullable fields to read as "required" + # (even if there is a default value!) + if not field.allow_null and not (hasattr(field, 'allow_blank') and field.allow_blank): + field_info['required'] = True + + # Introspect writable related fields + if field_info['type'] == 'field' and not field_info['read_only']: + + # If the field is a PrimaryKeyRelatedField, we can extract the model from the queryset + if isinstance(field, serializers.PrimaryKeyRelatedField): + model = field.queryset.model + else: + logger.debug("Could not extract model for:", field_info['label'], '->', field) + model = None + + if model: + # Mark this field as "related", and point to the URL where we can get the data! + field_info['type'] = 'related field' + field_info['model'] = model._meta.model_name + + # Special case for 'user' model + if field_info['model'] == 'user': + field_info['api_url'] = '/api/user/' + else: + field_info['api_url'] = model.get_api_url() + + return field_info diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 5822f8a19f..2831a23151 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -10,11 +10,13 @@ from django.db import models from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError from django.db.models.signals import pre_delete from django.dispatch import receiver from mptt.models import MPTTModel, TreeForeignKey +from mptt.exceptions import InvalidMove from .validators import validate_tree_name @@ -91,6 +93,15 @@ class InvenTreeTree(MPTTModel): parent: The item immediately above this one. An item with a null parent is a top-level item """ + def save(self, *args, **kwargs): + + try: + super().save(*args, **kwargs) + except InvalidMove: + raise ValidationError({ + 'parent': _("Invalid choice"), + }) + class Meta: abstract = True diff --git a/InvenTree/InvenTree/serializers.py b/InvenTree/InvenTree/serializers.py index f093255ff0..58d33697b7 100644 --- a/InvenTree/InvenTree/serializers.py +++ b/InvenTree/InvenTree/serializers.py @@ -2,19 +2,61 @@ Serializers used in various InvenTree apps """ - # -*- coding: utf-8 -*- from __future__ import unicode_literals + import os +from decimal import Decimal + from django.conf import settings from django.contrib.auth.models import User from django.core.exceptions import ValidationError as DjangoValidationError +from django.utils.translation import ugettext_lazy as _ + +from djmoney.contrib.django_rest_framework.fields import MoneyField +from djmoney.money import Money +from djmoney.utils import MONEY_CLASSES, get_currency_field_name from rest_framework import serializers +from rest_framework.utils import model_meta from rest_framework.fields import empty from rest_framework.exceptions import ValidationError +from rest_framework.serializers import DecimalField + + +class InvenTreeMoneySerializer(MoneyField): + """ + Custom serializer for 'MoneyField', + which ensures that passed values are numerically valid + + Ref: https://github.com/django-money/django-money/blob/master/djmoney/contrib/django_rest_framework/fields.py + """ + + def get_value(self, data): + """ + Test that the returned amount is a valid Decimal + """ + + amount = super(DecimalField, self).get_value(data) + + # Convert an empty string to None + if len(str(amount).strip()) == 0: + amount = None + + try: + if amount is not None: + amount = Decimal(amount) + except: + raise ValidationError(_("Must be a valid number")) + + currency = data.get(get_currency_field_name(self.field_name), self.default_currency) + + if currency and amount is not None and not isinstance(amount, MONEY_CLASSES) and amount is not empty: + return Money(amount, currency) + + return amount class UserSerializer(serializers.ModelSerializer): @@ -42,8 +84,90 @@ class InvenTreeModelSerializer(serializers.ModelSerializer): but also ensures that the underlying model class data are checked on validation. """ + def __init__(self, instance=None, data=empty, **kwargs): + + # self.instance = instance + + # If instance is None, we are creating a new instance + if instance is None and data is not empty: + + # Required to side-step immutability of a QueryDict + data = data.copy() + + # Add missing fields which have default values + ModelClass = self.Meta.model + + fields = model_meta.get_field_info(ModelClass) + + for field_name, field in fields.fields.items(): + + """ + Update the field IF (and ONLY IF): + - The field has a specified default value + - The field does not already have a value set + """ + if field.has_default() and field_name not in data: + + value = field.default + + # Account for callable functions + if callable(value): + try: + value = value() + except: + continue + + data[field_name] = value + + super().__init__(instance, data, **kwargs) + + def get_initial(self): + """ + Construct initial data for the serializer. + Use the 'default' values specified by the django model definition + """ + + initials = super().get_initial().copy() + + # Are we creating a new instance? + if self.instance is None: + ModelClass = self.Meta.model + + fields = model_meta.get_field_info(ModelClass) + + for field_name, field in fields.fields.items(): + + if field.has_default() and field_name not in initials: + + value = field.default + + # Account for callable functions + if callable(value): + try: + value = value() + except: + continue + + initials[field_name] = value + + return initials + + def save(self, **kwargs): + """ + Catch any django ValidationError thrown at the moment save() is called, + and re-throw as a DRF ValidationError + """ + + try: + super().save(**kwargs) + except (ValidationError, DjangoValidationError) as exc: + raise ValidationError(detail=serializers.as_serializer_error(exc)) + + return self.instance + def run_validation(self, data=empty): - """ Perform serializer validation. + """ + Perform serializer validation. In addition to running validators on the serializer fields, this class ensures that the underlying model is also validated. """ diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index fceaf9a58f..3b7c95e245 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -23,6 +23,7 @@ import moneyed import yaml from django.utils.translation import gettext_lazy as _ +from django.contrib.messages import constants as messages def _is_true(x): @@ -341,6 +342,7 @@ REST_FRAMEWORK = { 'InvenTree.permissions.RolePermission', ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', + 'DEFAULT_METADATA_CLASS': 'InvenTree.metadata.InvenTreeMetadata' } WSGI_APPLICATION = 'InvenTree.wsgi.application' @@ -521,10 +523,6 @@ for currency in CURRENCIES: print(f"Currency code '{currency}' is not supported") sys.exit(1) -BASE_CURRENCY = get_setting( - 'INVENTREE_BASE_CURRENCY', - CONFIG.get('base_currency', 'USD') -) # Custom currency exchange backend EXCHANGE_BACKEND = 'InvenTree.exchange.InvenTreeExchange' @@ -611,3 +609,9 @@ IMPORT_EXPORT_USE_TRANSACTIONS = True INTERNAL_IPS = [ '127.0.0.1', ] + +MESSAGE_TAGS = { + messages.SUCCESS: 'alert alert-block alert-success', + messages.ERROR: 'alert alert-block alert-danger', + messages.INFO: 'alert alert-block alert-info', +} diff --git a/InvenTree/InvenTree/static/css/bootstrap.min.css.map b/InvenTree/InvenTree/static/css/bootstrap.min.css.map new file mode 100644 index 0000000000..6c7fa40b98 --- /dev/null +++ b/InvenTree/InvenTree/static/css/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["less/normalize.less","less/print.less","bootstrap.css","dist/css/bootstrap.css","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":";;;;4EAQA,KACE,YAAA,WACA,yBAAA,KACA,qBAAA,KAOF,KACE,OAAA,EAaF,QAAA,MAAA,QAAA,WAAA,OAAA,OAAA,OAAA,OAAA,KAAA,KAAA,IAAA,QAAA,QAaE,QAAA,MAQF,MAAA,OAAA,SAAA,MAIE,QAAA,aACA,eAAA,SAQF,sBACE,QAAA,KACA,OAAA,EAQF,SAAA,SAEE,QAAA,KAUF,EACE,iBAAA,YAQF,SAAA,QAEE,QAAA,EAUF,YACE,cAAA,IAAA,OAOF,EAAA,OAEE,YAAA,IAOF,IACE,WAAA,OAQF,GACE,OAAA,MAAA,EACA,UAAA,IAOF,KACE,MAAA,KACA,WAAA,KAOF,MACE,UAAA,IAOF,IAAA,IAEE,SAAA,SACA,UAAA,IACA,YAAA,EACA,eAAA,SAGF,IACE,IAAA,MAGF,IACE,OAAA,OAUF,IACE,OAAA,EAOF,eACE,SAAA,OAUF,OACE,OAAA,IAAA,KAOF,GACE,OAAA,EAAA,mBAAA,YAAA,gBAAA,YACA,WAAA,YAOF,IACE,SAAA,KAOF,KAAA,IAAA,IAAA,KAIE,YAAA,UAAA,UACA,UAAA,IAkBF,OAAA,MAAA,SAAA,OAAA,SAKE,OAAA,EACA,KAAA,QACA,MAAA,QAOF,OACE,SAAA,QAUF,OAAA,OAEE,eAAA,KAWF,OAAA,wBAAA,kBAAA,mBAIE,mBAAA,OACA,OAAA,QAOF,iBAAA,qBAEE,OAAA,QAOF,yBAAA,wBAEE,QAAA,EACA,OAAA,EAQF,MACE,YAAA,OAWF,qBAAA,kBAEE,mBAAA,WAAA,gBAAA,WAAA,WAAA,WACA,QAAA,EASF,8CAAA,8CAEE,OAAA,KAQF,mBACE,mBAAA,YACA,gBAAA,YAAA,WAAA,YAAA,mBAAA,UASF,iDAAA,8CAEE,mBAAA,KAOF,SACE,QAAA,MAAA,OAAA,MACA,OAAA,EAAA,IACA,OAAA,IAAA,MAAA,OAQF,OACE,QAAA,EACA,OAAA,EAOF,SACE,SAAA,KAQF,SACE,YAAA,IAUF,MACE,eAAA,EACA,gBAAA,SAGF,GAAA,GAEE,QAAA,uFCjUF,aA7FI,EAAA,OAAA,QAGI,MAAA,eACA,YAAA,eACA,WAAA,cAAA,mBAAA,eACA,WAAA,eAGJ,EAAA,UAEI,gBAAA,UAGJ,cACI,QAAA,KAAA,WAAA,IAGJ,kBACI,QAAA,KAAA,YAAA,IAKJ,6BAAA,mBAEI,QAAA,GAGJ,WAAA,IAEI,OAAA,IAAA,MAAA,KC4KL,kBAAA,MDvKK,MC0KL,QAAA,mBDrKK,IE8KN,GDLC,kBAAA,MDrKK,ICwKL,UAAA,eCUD,GF5KM,GE2KN,EF1KM,QAAA,ECuKL,OAAA,ECSD,GF3KM,GCsKL,iBAAA,MD/JK,QCkKL,QAAA,KCSD,YFtKU,oBCiKT,iBAAA,eD7JK,OCgKL,OAAA,IAAA,MAAA,KD5JK,OC+JL,gBAAA,mBCSD,UFpKU,UC+JT,iBAAA,eDzJS,mBEkKV,mBDLC,OAAA,IAAA,MAAA,gBEjPD,WACA,YAAA,uBFsPD,IAAA,+CE7OC,IAAK,sDAAuD,4BAA6B,iDAAkD,gBAAiB,gDAAiD,eAAgB,+CAAgD,mBAAoB,2EAA4E,cAE7W,WACA,SAAA,SACA,IAAA,IACA,QAAA,aACA,YAAA,uBACA,WAAA,OACA,YAAA,IACA,YAAA,EAIkC,uBAAA,YAAW,wBAAA,UACX,2BAAW,QAAA,QAEX,uBDuPlC,QAAS,QCtPyB,sBFiPnC,uBEjP8C,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,qBAAW,QAAA,QACX,0BAAW,QAAA,QACX,qBAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,sBAAW,QAAA,QACX,yBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,+BAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,gCAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,gCAAW,QAAA,QACX,gCAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,0BAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,mCAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,sBAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,0BAAW,QAAA,QACX,4BAAW,QAAA,QACX,qCAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,mCAAW,QAAA,QACX,uCAAW,QAAA,QACX,gCAAW,QAAA,QACX,oCAAW,QAAA,QACX,qCAAW,QAAA,QACX,yCAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,iCAAW,QAAA,QACX,oCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,qBAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QASX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,+BAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,mCAAW,QAAA,QACX,4BAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,kCAAW,QAAA,QACX,mCAAW,QAAA,QACX,sCAAW,QAAA,QACX,0CAAW,QAAA,QACX,oCAAW,QAAA,QACX,wCAAW,QAAA,QACX,qCAAW,QAAA,QACX,iCAAW,QAAA,QACX,gCAAW,QAAA,QACX,kCAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QCtS/C,0BCgEE,QAAA,QHi+BF,EDNC,mBAAA,WGxhCI,gBAAiB,WFiiCZ,WAAY,WGl+BZ,OADL,QJg+BJ,mBAAA,WGthCI,gBAAiB,WACpB,WAAA,WHyhCD,KGrhCC,UAAW,KAEX,4BAAA,cAEA,KACA,YAAA,iBAAA,UAAA,MAAA,WHuhCD,UAAA,KGnhCC,YAAa,WF4hCb,MAAO,KACP,iBAAkB,KExhClB,OADA,MAEA,OHqhCD,SG/gCC,YAAa,QACb,UAAA,QACA,YAAA,QAEA,EFwhCA,MAAO,QEthCL,gBAAA,KAIF,QH8gCD,QKjkCC,MAAA,QACA,gBAAA,UF6DF,QACE,QAAA,IAAA,KAAA,yBHygCD,eAAA,KGlgCC,OHqgCD,OAAA,ECSD,IACE,eAAgB,ODDjB,4BM/kCC,0BLklCF,gBKnlCE,iBADA,eH4EA,QAAS,MACT,UAAA,KHugCD,OAAA,KGhgCC,aACA,cAAA,IAEA,eACA,QAAA,aC6FA,UAAA,KACK,OAAA,KACG,QAAA,IEvLR,YAAA,WACA,iBAAA,KACA,OAAA,IAAA,MAAA,KN+lCD,cAAA,IGjgCC,mBAAoB,IAAI,IAAI,YAC5B,cAAA,IAAA,IAAA,YHmgCD,WAAA,IAAA,IAAA,YG5/BC,YACA,cAAA,IAEA,GH+/BD,WAAA,KGv/BC,cAAe,KACf,OAAA,EACA,WAAA,IAAA,MAAA,KAEA,SACA,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EHy/BD,OAAA,KGj/BC,SAAA,OF0/BA,KAAM,cEx/BJ,OAAA,EAEA,0BACA,yBACA,SAAA,OACA,MAAA,KHm/BH,OAAA,KGx+BC,OAAQ,EACR,SAAA,QH0+BD,KAAA,KCSD,cACE,OAAQ,QAQV,IACA,IMlpCE,IACA,IACA,IACA,INwoCF,GACA,GACA,GACA,GACA,GACA,GDAC,YAAA,QOlpCC,YAAa,IN2pCb,YAAa,IACb,MAAO,QAoBT,WAZA,UAaA,WAZA,UM5pCI,WN6pCJ,UM5pCI,WN6pCJ,UM5pCI,WN6pCJ,UDMC,WCLD,UACA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SMppCE,YAAa,INwqCb,YAAa,EACb,MAAO,KAGT,IMxqCE,IAJF,IN2qCA,GAEA,GDLC,GCSC,WAAY,KACZ,cAAe,KASjB,WANA,UDCC,WCCD,UM5qCA,WN8qCA,UACA,UANA,SM5qCI,UN8qCJ,SM3qCA,UN6qCA,SAQE,UAAW,IAGb,IMprCE,IAJF,INurCA,GAEA,GDLC,GCSC,WAAY,KACZ,cAAe,KASjB,WANA,UDCC,WCCD,UMvrCA,WNyrCA,UACA,UANA,SMxrCI,UN0rCJ,SMtrCA,UNwrCA,SMxrCU,UAAA,IACV,IAAA,GAAU,UAAA,KACV,IAAA,GAAU,UAAA,KACV,IAAA,GAAU,UAAA,KACV,IAAA,GAAU,UAAA,KACV,IAAA,GAAU,UAAA,KAOR,IADF,GPssCC,UAAA,KCSD,EMzsCE,OAAA,EAAA,EAAA,KAEA,MPosCD,cAAA,KO/rCC,UAAW,KAwOX,YAAa,IA1OX,YAAA,IPssCH,yBO7rCC,MNssCE,UAAW,MMjsCf,OAAA,MAEE,UAAA,IAKF,MP0rCC,KO1rCsB,QAAA,KP6rCtB,iBAAA,QO5rCsB,WP+rCtB,WAAA,KO9rCsB,YPisCtB,WAAA,MOhsCsB,aPmsCtB,WAAA,OOlsCsB,cPqsCtB,WAAA,QOlsCsB,aPqsCtB,YAAA,OOpsCsB,gBPusCtB,eAAA,UOtsCsB,gBPysCtB,eAAA,UOrsCC,iBPwsCD,eAAA,WQ3yCC,YR8yCD,MAAA,KCSD,cOpzCI,MAAA,QAHF,qBDwGF,qBP6sCC,MAAA,QCSD,cO3zCI,MAAA,QAHF,qBD2GF,qBPitCC,MAAA,QCSD,WOl0CI,MAAA,QAHF,kBD8GF,kBPqtCC,MAAA,QCSD,cOz0CI,MAAA,QAHF,qBDiHF,qBPytCC,MAAA,QCSD,aOh1CI,MAAA,QDwHF,oBAHF,oBExHE,MAAA,QACA,YR01CA,MAAO,KQx1CL,iBAAA,QAHF,mBF8HF,mBP2tCC,iBAAA,QCSD,YQ/1CI,iBAAA,QAHF,mBFiIF,mBP+tCC,iBAAA,QCSD,SQt2CI,iBAAA,QAHF,gBFoIF,gBPmuCC,iBAAA,QCSD,YQ72CI,iBAAA,QAHF,mBFuIF,mBPuuCC,iBAAA,QCSD,WQp3CI,iBAAA,QF6IF,kBADF,kBAEE,iBAAA,QPsuCD,aO7tCC,eAAgB,INsuChB,OAAQ,KAAK,EAAE,KMpuCf,cAAA,IAAA,MAAA,KAFF,GPkuCC,GCSC,WAAY,EACZ,cAAe,KM9tCf,MP0tCD,MO3tCD,MAPI,MASF,cAAA,EAIF,eALE,aAAA,EACA,WAAA,KPkuCD,aO9tCC,aAAc,EAKZ,YAAA,KACA,WAAA,KP6tCH,gBOvtCC,QAAS,aACT,cAAA,IACA,aAAA,IAEF,GNguCE,WAAY,EM9tCZ,cAAA,KAGA,GADF,GP0tCC,YAAA,WOttCC,GPytCD,YAAA,IOnnCD,GAvFM,YAAA,EAEA,yBACA,kBGtNJ,MAAA,KACA,MAAA,MACA,SAAA,OVq6CC,MAAA,KO7nCC,WAAY,MAhFV,cAAA,SPgtCH,YAAA,OOtsCD,kBNgtCE,YAAa,OM1sCjB,0BPssCC,YOrsCC,OAAA,KA9IqB,cAAA,IAAA,OAAA,KAmJvB,YACE,UAAA,IACA,eAAA,UAEA,WPssCD,QAAA,KAAA,KOjsCG,OAAA,EAAA,EAAA,KN0sCF,UAAW,OACX,YAAa,IAAI,MAAM,KMptCzB,yBP+sCC,wBO/sCD,yBNytCE,cAAe,EMnsCb,kBAFA,kBACA,iBPksCH,QAAA,MO/rCG,UAAA,INwsCF,YAAa,WACb,MAAO,KMhsCT,yBP2rCC,yBO3rCD,wBAEE,QAAA,cAEA,oBACA,sBACA,cAAA,KP6rCD,aAAA,EOvrCG,WAAA,MNgsCF,aAAc,IAAI,MAAM,KACxB,YAAa,EMhsCX,kCNksCJ,kCMnsCe,iCACX,oCNmsCJ,oCDLC,mCCUC,QAAS,GMjsCX,iCNmsCA,iCMzsCM,gCAOJ,mCNmsCF,mCDLC,kCO7rCC,QAAA,cPksCD,QWv+CC,cAAe,KVg/Cf,WAAY,OACZ,YAAa,WU7+Cb,KXy+CD,IWr+CD,IACE,KACA,YAAA,MAAA,OAAA,SAAA,cAAA,UAEA,KACA,QAAA,IAAA,IXu+CD,UAAA,IWn+CC,MAAO,QACP,iBAAA,QACA,cAAA,IAEA,IACA,QAAA,IAAA,IACA,UAAA,IV4+CA,MU5+CA,KXq+CD,iBAAA,KW3+CC,cAAe,IASb,mBAAA,MAAA,EAAA,KAAA,EAAA,gBACA,WAAA,MAAA,EAAA,KAAA,EAAA,gBAEA,QV6+CF,QU7+CE,EXq+CH,UAAA,KWh+CC,YAAa,IACb,mBAAA,KACA,WAAA,KAEA,IACA,QAAA,MACA,QAAA,MACA,OAAA,EAAA,EAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,WAAA,UXk+CD,UAAA,WW7+CC,iBAAkB,QAehB,OAAA,IAAA,MAAA,KACA,cAAA,IAEA,SACA,QAAA,EACA,UAAA,QXi+CH,MAAA,QW59CC,YAAa,SACb,iBAAA,YACA,cAAA,EC1DF,gBCHE,WAAA,MACA,WAAA,OAEA,Wb8hDD,cAAA,KYxhDC,aAAA,KAqEA,aAAc,KAvEZ,YAAA,KZ+hDH,yBY1hDC,WAkEE,MAAO,OZ69CV,yBY5hDC,WA+DE,MAAO,OZk+CV,0BYzhDC,WCvBA,MAAA,QAGA,iBbmjDD,cAAA,KYthDC,aAAc,KCvBd,aAAA,KACA,YAAA,KCAE,KACE,aAAA,MAEA,YAAA,MAGA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UdgjDL,SAAA,SchiDG,WAAA,IACE,cAAA,KdkiDL,aAAA,Kc1hDG,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,Ud6hDH,MAAA,Kc7hDG,WdgiDH,MAAA,KchiDG,WdmiDH,MAAA,acniDG,WdsiDH,MAAA,actiDG,UdyiDH,MAAA,IcziDG,Ud4iDH,MAAA,ac5iDG,Ud+iDH,MAAA,ac/iDG,UdkjDH,MAAA,IcljDG,UdqjDH,MAAA,acrjDG,UdwjDH,MAAA,acxjDG,Ud2jDH,MAAA,Ic3jDG,Ud8jDH,MAAA,ac/iDG,UdkjDH,MAAA,YcljDG,gBdqjDH,MAAA,KcrjDG,gBdwjDH,MAAA,acxjDG,gBd2jDH,MAAA,ac3jDG,ed8jDH,MAAA,Ic9jDG,edikDH,MAAA,acjkDG,edokDH,MAAA,acpkDG,edukDH,MAAA,IcvkDG,ed0kDH,MAAA,ac1kDG,ed6kDH,MAAA,ac7kDG,edglDH,MAAA,IchlDG,edmlDH,MAAA,ac9kDG,edilDH,MAAA,YchmDG,edmmDH,MAAA,KcnmDG,gBdsmDH,KAAA,KctmDG,gBdymDH,KAAA,aczmDG,gBd4mDH,KAAA,ac5mDG,ed+mDH,KAAA,Ic/mDG,edknDH,KAAA,aclnDG,edqnDH,KAAA,acrnDG,edwnDH,KAAA,IcxnDG,ed2nDH,KAAA,ac3nDG,ed8nDH,KAAA,ac9nDG,edioDH,KAAA,IcjoDG,edooDH,KAAA,ac/nDG,edkoDH,KAAA,YcnnDG,edsnDH,KAAA,KctnDG,kBdynDH,YAAA,KcznDG,kBd4nDH,YAAA,ac5nDG,kBd+nDH,YAAA,ac/nDG,iBdkoDH,YAAA,IcloDG,iBdqoDH,YAAA,acroDG,iBdwoDH,YAAA,acxoDG,iBd2oDH,YAAA,Ic3oDG,iBd8oDH,YAAA,ac9oDG,iBdipDH,YAAA,acjpDG,iBdopDH,YAAA,IcppDG,iBdupDH,YAAA,acvpDG,iBd0pDH,YAAA,Yc5rDG,iBACE,YAAA,EAOJ,yBACE,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,Ud0rDD,MAAA,Kc1rDC,Wd6rDD,MAAA,Kc7rDC,WdgsDD,MAAA,achsDC,WdmsDD,MAAA,acnsDC,UdssDD,MAAA,IctsDC,UdysDD,MAAA,aczsDC,Ud4sDD,MAAA,ac5sDC,Ud+sDD,MAAA,Ic/sDC,UdktDD,MAAA,acltDC,UdqtDD,MAAA,acrtDC,UdwtDD,MAAA,IcxtDC,Ud2tDD,MAAA,ac5sDC,Ud+sDD,MAAA,Yc/sDC,gBdktDD,MAAA,KcltDC,gBdqtDD,MAAA,acrtDC,gBdwtDD,MAAA,acxtDC,ed2tDD,MAAA,Ic3tDC,ed8tDD,MAAA,ac9tDC,ediuDD,MAAA,acjuDC,edouDD,MAAA,IcpuDC,eduuDD,MAAA,acvuDC,ed0uDD,MAAA,ac1uDC,ed6uDD,MAAA,Ic7uDC,edgvDD,MAAA,ac3uDC,ed8uDD,MAAA,Yc7vDC,edgwDD,MAAA,KchwDC,gBdmwDD,KAAA,KcnwDC,gBdswDD,KAAA,actwDC,gBdywDD,KAAA,aczwDC,ed4wDD,KAAA,Ic5wDC,ed+wDD,KAAA,ac/wDC,edkxDD,KAAA,aclxDC,edqxDD,KAAA,IcrxDC,edwxDD,KAAA,acxxDC,ed2xDD,KAAA,ac3xDC,ed8xDD,KAAA,Ic9xDC,ediyDD,KAAA,ac5xDC,ed+xDD,KAAA,YchxDC,edmxDD,KAAA,KcnxDC,kBdsxDD,YAAA,KctxDC,kBdyxDD,YAAA,aczxDC,kBd4xDD,YAAA,ac5xDC,iBd+xDD,YAAA,Ic/xDC,iBdkyDD,YAAA,aclyDC,iBdqyDD,YAAA,acryDC,iBdwyDD,YAAA,IcxyDC,iBd2yDD,YAAA,ac3yDC,iBd8yDD,YAAA,ac9yDC,iBdizDD,YAAA,IcjzDC,iBdozDD,YAAA,acpzDC,iBduzDD,YAAA,YY9yDD,iBE3CE,YAAA,GAQF,yBACE,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,Udw1DD,MAAA,Kcx1DC,Wd21DD,MAAA,Kc31DC,Wd81DD,MAAA,ac91DC,Wdi2DD,MAAA,acj2DC,Udo2DD,MAAA,Icp2DC,Udu2DD,MAAA,acv2DC,Ud02DD,MAAA,ac12DC,Ud62DD,MAAA,Ic72DC,Udg3DD,MAAA,ach3DC,Udm3DD,MAAA,acn3DC,Uds3DD,MAAA,Ict3DC,Udy3DD,MAAA,ac12DC,Ud62DD,MAAA,Yc72DC,gBdg3DD,MAAA,Kch3DC,gBdm3DD,MAAA,acn3DC,gBds3DD,MAAA,act3DC,edy3DD,MAAA,Icz3DC,ed43DD,MAAA,ac53DC,ed+3DD,MAAA,ac/3DC,edk4DD,MAAA,Icl4DC,edq4DD,MAAA,acr4DC,edw4DD,MAAA,acx4DC,ed24DD,MAAA,Ic34DC,ed84DD,MAAA,acz4DC,ed44DD,MAAA,Yc35DC,ed85DD,MAAA,Kc95DC,gBdi6DD,KAAA,Kcj6DC,gBdo6DD,KAAA,acp6DC,gBdu6DD,KAAA,acv6DC,ed06DD,KAAA,Ic16DC,ed66DD,KAAA,ac76DC,edg7DD,KAAA,ach7DC,edm7DD,KAAA,Icn7DC,eds7DD,KAAA,act7DC,edy7DD,KAAA,acz7DC,ed47DD,KAAA,Ic57DC,ed+7DD,KAAA,ac17DC,ed67DD,KAAA,Yc96DC,edi7DD,KAAA,Kcj7DC,kBdo7DD,YAAA,Kcp7DC,kBdu7DD,YAAA,acv7DC,kBd07DD,YAAA,ac17DC,iBd67DD,YAAA,Ic77DC,iBdg8DD,YAAA,ach8DC,iBdm8DD,YAAA,acn8DC,iBds8DD,YAAA,Ict8DC,iBdy8DD,YAAA,acz8DC,iBd48DD,YAAA,ac58DC,iBd+8DD,YAAA,Ic/8DC,iBdk9DD,YAAA,acl9DC,iBdq9DD,YAAA,YYz8DD,iBE9CE,YAAA,GAQF,0BACE,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,Uds/DD,MAAA,Kct/DC,Wdy/DD,MAAA,Kcz/DC,Wd4/DD,MAAA,ac5/DC,Wd+/DD,MAAA,ac//DC,UdkgED,MAAA,IclgEC,UdqgED,MAAA,acrgEC,UdwgED,MAAA,acxgEC,Ud2gED,MAAA,Ic3gEC,Ud8gED,MAAA,ac9gEC,UdihED,MAAA,acjhEC,UdohED,MAAA,IcphEC,UduhED,MAAA,acxgEC,Ud2gED,MAAA,Yc3gEC,gBd8gED,MAAA,Kc9gEC,gBdihED,MAAA,acjhEC,gBdohED,MAAA,acphEC,eduhED,MAAA,IcvhEC,ed0hED,MAAA,ac1hEC,ed6hED,MAAA,ac7hEC,edgiED,MAAA,IchiEC,edmiED,MAAA,acniEC,edsiED,MAAA,actiEC,edyiED,MAAA,IcziEC,ed4iED,MAAA,acviEC,ed0iED,MAAA,YczjEC,ed4jED,MAAA,Kc5jEC,gBd+jED,KAAA,Kc/jEC,gBdkkED,KAAA,aclkEC,gBdqkED,KAAA,acrkEC,edwkED,KAAA,IcxkEC,ed2kED,KAAA,ac3kEC,ed8kED,KAAA,ac9kEC,edilED,KAAA,IcjlEC,edolED,KAAA,acplEC,edulED,KAAA,acvlEC,ed0lED,KAAA,Ic1lEC,ed6lED,KAAA,acxlEC,ed2lED,KAAA,Yc5kEC,ed+kED,KAAA,Kc/kEC,kBdklED,YAAA,KcllEC,kBdqlED,YAAA,acrlEC,kBdwlED,YAAA,acxlEC,iBd2lED,YAAA,Ic3lEC,iBd8lED,YAAA,ac9lEC,iBdimED,YAAA,acjmEC,iBdomED,YAAA,IcpmEC,iBdumED,YAAA,acvmEC,iBd0mED,YAAA,ac1mEC,iBd6mED,YAAA,Ic7mEC,iBdgnED,YAAA,achnEC,iBdmnED,YAAA,YetrED,iBACA,YAAA,GAGA,MACA,iBAAA,YAEA,QfyrED,YAAA,IevrEC,eAAgB,IAChB,MAAA,KfyrED,WAAA,KelrEC,GACA,WAAA,KfsrED,OexrEC,MAAO,KdmsEP,UAAW,KACX,cAAe,KcvrET,mBd0rER,mBczrEQ,mBAHA,mBACA,mBd0rER,mBDHC,QAAA,IensEC,YAAa,WAoBX,eAAA,IACA,WAAA,IAAA,MAAA,KArBJ,mBdktEE,eAAgB,OAChB,cAAe,IAAI,MAAM,KDJ1B,uCCMD,uCcrtEA,wCdstEA,wCclrEI,2CANI,2CforEP,WAAA,EezqEG,mBf4qEH,WAAA,IAAA,MAAA,KCWD,cACE,iBAAkB,Kc/pEpB,6BdkqEA,6BcjqEE,6BAZM,6BfsqEP,6BCMD,6BDHC,QAAA,ICWD,gBACE,OAAQ,IAAI,MAAM,Kc1qEpB,4Bd6qEA,4Bc7qEA,4BAQQ,4Bf8pEP,4BCMD,4Bc7pEM,OAAA,IAAA,MAAA,KAYF,4BAFJ,4BfopEC,oBAAA,IevoEG,yCf0oEH,iBAAA,QehoEC,4BACA,iBAAA,QfooED,uBe9nEG,SAAA,OdyoEF,QAAS,acxoEL,MAAA,KAEA,sBfioEL,sBgB7wEC,SAAA,OfwxEA,QAAS,WACT,MAAO,KAST,0BerxEE,0Bf+wEF,0BAGA,0BexxEM,0BAMJ,0BfgxEF,0BAGA,0BACA,0BDNC,0BCAD,0BAGA,0BASE,iBAAkB,QDLnB,sCgBlyEC,sCAAA,oCfyyEF,sCetxEM,sCf2xEJ,iBAAkB,QASpB,2Be1yEE,2BfoyEF,2BAGA,2Be7yEM,2BAMJ,2BfqyEF,2BAGA,2BACA,2BDNC,2BCAD,2BAGA,2BASE,iBAAkB,QDLnB,uCgBvzEC,uCAAA,qCf8zEF,uCe3yEM,uCfgzEJ,iBAAkB,QASpB,wBe/zEE,wBfyzEF,wBAGA,wBel0EM,wBAMJ,wBf0zEF,wBAGA,wBACA,wBDNC,wBCAD,wBAGA,wBASE,iBAAkB,QDLnB,oCgB50EC,oCAAA,kCfm1EF,oCeh0EM,oCfq0EJ,iBAAkB,QASpB,2Bep1EE,2Bf80EF,2BAGA,2Bev1EM,2BAMJ,2Bf+0EF,2BAGA,2BACA,2BDNC,2BCAD,2BAGA,2BASE,iBAAkB,QDLnB,uCgBj2EC,uCAAA,qCfw2EF,uCer1EM,uCf01EJ,iBAAkB,QASpB,0Bez2EE,0Bfm2EF,0BAGA,0Be52EM,0BAMJ,0Bfo2EF,0BAGA,0BACA,0BDNC,0BCAD,0BAGA,0BASE,iBAAkB,QDLnB,sCehtEC,sCADF,oCdwtEA,sCe12EM,sCDoJJ,iBAAA,QA6DF,kBACE,WAAY,KA3DV,WAAA,KAEA,oCACA,kBACA,MAAA,KfotED,cAAA,Ke7pEC,WAAY,OAnDV,mBAAA,yBfmtEH,OAAA,IAAA,MAAA,KCWD,yBACE,cAAe,Ec5qEjB,qCd+qEA,qCcjtEI,qCARM,qCfktET,qCCMD,qCDHC,YAAA,OCWD,kCACE,OAAQ,EcvrEV,0Dd0rEA,0Dc1rEA,0DAzBU,0Df4sET,0DCMD,0DAME,YAAa,Ec/rEf,yDdksEA,yDclsEA,yDArBU,yDfgtET,yDCMD,yDAME,aAAc,EDLjB,yDe1sEW,yDEzNV,yDjBk6EC,yDiBj6ED,cAAA,GAMA,SjBk6ED,UAAA,EiB/5EC,QAAS,EACT,OAAA,EACA,OAAA,EAEA,OACA,QAAA,MACA,MAAA,KACA,QAAA,EACA,cAAA,KACA,UAAA,KjBi6ED,YAAA,QiB95EC,MAAO,KACP,OAAA,EACA,cAAA,IAAA,MAAA,QAEA,MjBg6ED,QAAA,aiBr5EC,UAAW,Kb4BX,cAAA,IACG,YAAA,IJ63EJ,mBiBr5EC,mBAAoB,WhBg6EjB,gBAAiB,WgB95EpB,WAAA,WjBy5ED,qBiBv5EC,kBAGA,OAAQ,IAAI,EAAE,EACd,WAAA,MjBs5ED,YAAA,OiBj5EC,iBACA,QAAA,MAIF,kBhB25EE,QAAS,MgBz5ET,MAAA,KAIF,iBAAA,ahB05EE,OAAQ,KI99ER,uBY2EF,2BjB64EC,wBiB54EC,QAAA,IAAA,KAAA,yBACA,eAAA,KAEA,OACA,QAAA,MjB+4ED,YAAA,IiBr3EC,UAAW,KACX,YAAA,WACA,MAAA,KAEA,cACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KbxDA,iBAAA,KACQ,iBAAA,KAyHR,OAAA,IAAA,MAAA,KACK,cAAA,IACG,mBAAA,MAAA,EAAA,IAAA,IAAA,iBJwzET,WAAA,MAAA,EAAA,IAAA,IAAA,iBkBh8EC,mBAAA,aAAA,YAAA,KAAA,mBAAA,YAAA,KACE,cAAA,aAAA,YAAA,KAAA,WAAA,YAAA,KACA,WAAA,aAAA,YAAA,KAAA,WAAA,YAAA,KdWM,oBJy7ET,aAAA,QIx5EC,QAAA,EACE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,qBACA,WAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,qBAEF,gCAA0B,MAAA,KJ25E3B,QAAA,EI15EiC,oCJ65EjC,MAAA,KiBh4EG,yCACA,MAAA,KAQF,0BhBs4EA,iBAAkB,YAClB,OAAQ,EgBn4EN,wBjB63EH,wBiB13EC,iChBq4EA,iBAAkB,KgBn4EhB,QAAA,EAIF,wBACE,iCjB03EH,OAAA,YiB72EC,sBjBg3ED,OAAA,KiB91EG,mBhB02EF,mBAAoB,KAEtB,qDgB32EM,8BjBo2EH,8BiBj2EC,wCAAA,+BhB62EA,YAAa,KgB32EX,iCjBy2EH,iCiBt2EC,2CAAA,kChB02EF,0BACA,0BACA,oCACA,2BAKE,YAAa,KgBh3EX,iCjB82EH,iCACF,2CiBp2EC,kChBu2EA,0BACA,0BACA,oCACA,2BgBz2EA,YAAA,MhBi3EF,YgBv2EE,cAAA,KAGA,UADA,OjBi2ED,SAAA,SiBr2EC,QAAS,MhBg3ET,WAAY,KgBx2EV,cAAA,KAGA,gBADA,aAEA,WAAA,KjBi2EH,aAAA,KiB91EC,cAAe,EhBy2Ef,YAAa,IACb,OAAQ,QgBp2ER,+BjBg2ED,sCiBl2EC,yBACA,gCAIA,SAAU,ShBw2EV,WAAY,MgBt2EZ,YAAA,MAIF,oBAAA,cAEE,WAAA,KAGA,iBADA,cAEA,SAAA,SACA,QAAA,aACA,aAAA,KjB61ED,cAAA,EiB31EC,YAAa,IhBs2Eb,eAAgB,OgBp2EhB,OAAA,QAUA,kCjBo1ED,4BCWC,WAAY,EACZ,YAAa,KgBv1Eb,wCAAA,qCjBm1ED,8BCOD,+BgBh2EI,2BhB+1EJ,4BAME,OAAQ,YDNT,0BiBv1EG,uBAMF,oCAAA,iChB61EA,OAAQ,YDNT,yBiBp1EK,sBAaJ,mCAFF,gCAGE,OAAA,YAGA,qBjBy0ED,WAAA,KiBv0EC,YAAA,IhBk1EA,eAAgB,IgBh1Ed,cAAA,EjB00EH,8BiB5zED,8BCnQE,cAAA,EACA,aAAA,EAEA,UACA,OAAA,KlBkkFD,QAAA,IAAA,KkBhkFC,UAAA,KACE,YAAA,IACA,cAAA,IAGF,gBjB0kFA,OAAQ,KiBxkFN,YAAA,KD2PA,0BAFJ,kBAGI,OAAA,KAEA,6BACA,OAAA,KjBy0EH,QAAA,IAAA,KiB/0EC,UAAW,KAST,YAAA,IACA,cAAA,IAVJ,mChB81EE,OAAQ,KgBh1EN,YAAA,KAGA,6CAjBJ,qCAkBI,OAAA,KAEA,oCACA,OAAA,KjBy0EH,WAAA,KiBr0EC,QAAS,IAAI,KC/Rb,UAAA,KACA,YAAA,IAEA,UACA,OAAA,KlBumFD,QAAA,KAAA,KkBrmFC,UAAA,KACE,YAAA,UACA,cAAA,IAGF,gBjB+mFA,OAAQ,KiB7mFN,YAAA,KDuRA,0BAFJ,kBAGI,OAAA,KAEA,6BACA,OAAA,KjBk1EH,QAAA,KAAA,KiBx1EC,UAAW,KAST,YAAA,UACA,cAAA,IAVJ,mChBu2EE,OAAQ,KgBz1EN,YAAA,KAGA,6CAjBJ,qCAkBI,OAAA,KAEA,oCACA,OAAA,KjBk1EH,WAAA,KiBz0EC,QAAS,KAAK,KAEd,UAAA,KjB00ED,YAAA,UiBt0EG,cjBy0EH,SAAA,SiBp0EC,4BACA,cAAA,OAEA,uBACA,SAAA,SACA,IAAA,EACA,MAAA,EACA,QAAA,EACA,QAAA,MACA,MAAA,KjBu0ED,OAAA,KiBr0EC,YAAa,KhBg1Eb,WAAY,OACZ,eAAgB,KDLjB,oDiBv0EC,uCADA,iCAGA,MAAO,KhBg1EP,OAAQ,KACR,YAAa,KDLd,oDiBv0EC,uCADA,iCAKA,MAAO,KhB80EP,OAAQ,KACR,YAAa,KAKf,uBAEA,8BAJA,4BADA,yBAEA,oBAEA,2BDNC,4BkBruFG,mCAJA,yBD0ZJ,gCbvWE,MAAA,QJ2rFD,2BkBxuFG,aAAA,QACE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBd4CJ,WAAA,MAAA,EAAA,IAAA,IAAA,iBJgsFD,iCiBz1EC,aAAc,QC5YZ,mBAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QACA,WAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QlByuFH,gCiB91EC,MAAO,QCtYL,iBAAA,QlBuuFH,aAAA,QCWD,oCACE,MAAO,QAKT,uBAEA,8BAJA,4BADA,yBAEA,oBAEA,2BDNC,4BkBnwFG,mCAJA,yBD6ZJ,gCb1WE,MAAA,QJytFD,2BkBtwFG,aAAA,QACE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBd4CJ,WAAA,MAAA,EAAA,IAAA,IAAA,iBJ8tFD,iCiBp3EC,aAAc,QC/YZ,mBAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QACA,WAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QlBuwFH,gCiBz3EC,MAAO,QCzYL,iBAAA,QlBqwFH,aAAA,QCWD,oCACE,MAAO,QAKT,qBAEA,4BAJA,0BADA,uBAEA,kBAEA,yBDNC,0BkBjyFG,iCAJA,uBDgaJ,8Bb7WE,MAAA,QJuvFD,yBkBpyFG,aAAA,QACE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBd4CJ,WAAA,MAAA,EAAA,IAAA,IAAA,iBJ4vFD,+BiB/4EC,aAAc,QClZZ,mBAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QACA,WAAA,MAAA,EAAA,IAAA,IAAA,iBAAA,EAAA,EAAA,IAAA,QlBqyFH,8BiBp5EC,MAAO,QC5YL,iBAAA,QlBmyFH,aAAA,QiB/4EG,kCjBk5EH,MAAA,QiB/4EG,2CjBk5EH,IAAA,KiBv4EC,mDACA,IAAA,EAEA,YjB04ED,QAAA,MiBvzEC,WAAY,IAwEZ,cAAe,KAtIX,MAAA,QAEA,yBjBy3EH,yBiBrvEC,QAAS,aA/HP,cAAA,EACA,eAAA,OjBw3EH,2BiB1vEC,QAAS,aAxHP,MAAA,KjBq3EH,eAAA,OiBj3EG,kCACA,QAAA,aAmHJ,0BhB4wEE,QAAS,aACT,eAAgB,OgBr3Ed,wCjB82EH,6CiBtwED,2CjBywEC,MAAA,KiB72EG,wCACA,MAAA,KAmGJ,4BhBwxEE,cAAe,EgBp3Eb,eAAA,OAGA,uBADA,oBjB82EH,QAAA,aiBpxEC,WAAY,EhB+xEZ,cAAe,EgBr3EX,eAAA,OAsFN,6BAAA,0BAjFI,aAAA,EAiFJ,4CjB6xEC,sCiBx2EG,SAAA,SjB22EH,YAAA,EiBh2ED,kDhB42EE,IAAK,GgBl2EL,2BjB+1EH,kCiBh2EG,wBAEA,+BAXF,YAAa,IhBo3Eb,WAAY,EgBn2EV,cAAA,EJviBF,2BIshBF,wBJrhBE,WAAA,KI4jBA,6BAyBA,aAAc,MAnCV,YAAA,MAEA,yBjBw1EH,gCACF,YAAA,IiBx3EG,cAAe,EAwCf,WAAA,OAwBJ,sDAdQ,MAAA,KjB80EL,yBACF,+CiBn0EC,YAAA,KAEE,UAAW,MjBs0EZ,yBACF,+CmBp6FG,YAAa,IACf,UAAA,MAGA,KACA,QAAA,aACA,QAAA,IAAA,KAAA,cAAA,EACA,UAAA,KACA,YAAA,IACA,YAAA,WACA,WAAA,OC0CA,YAAA,OACA,eAAA,OACA,iBAAA,aACA,aAAA,ahB+JA,OAAA,QACG,oBAAA,KACC,iBAAA,KACI,gBAAA,KJ+tFT,YAAA,KmBv6FG,iBAAA,KlBm7FF,OAAQ,IAAI,MAAM,YAClB,cAAe,IkB96Ff,kBdzBA,kBACA,WLk8FD,kBCOD,kBADA,WAME,QAAS,IAAI,KAAK,yBAClB,eAAgB,KkBh7FhB,WnBy6FD,WmB56FG,WlBw7FF,MAAO,KkBn7FL,gBAAA,Kf6BM,YADR,YJk5FD,iBAAA,KmBz6FC,QAAA,ElBq7FA,mBAAoB,MAAM,EAAE,IAAI,IAAI,iBAC5B,WAAY,MAAM,EAAE,IAAI,IAAI,iBoBh+FpC,cAGA,ejB8DA,wBACQ,OAAA,YJ05FT,OAAA,kBmBz6FG,mBAAA,KlBq7FM,WAAY,KkBn7FhB,QAAA,IASN,eC3DE,yBACA,eAAA,KpBi+FD,aoB99FC,MAAA,KnB0+FA,iBAAkB,KmBx+FhB,aAAA,KpBk+FH,mBoBh+FO,mBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpBi+FH,mBoB99FC,MAAA,KnB0+FA,iBAAkB,QAClB,aAAc,QmBt+FR,oBADJ,oBpBi+FH,mCoB99FG,MAAA,KnB0+FF,iBAAkB,QAClB,aAAc,QmBt+FN,0BnB4+FV,0BAHA,0BmB1+FM,0BnB4+FN,0BAHA,0BDFC,yCoBx+FK,yCnB4+FN,yCmBv+FE,MAAA,KnB++FA,iBAAkB,QAClB,aAAc,QmBx+FZ,oBpBg+FH,oBoBh+FG,mCnB6+FF,iBAAkB,KmBz+FV,4BnB8+FV,4BAHA,4BDHC,6BCOD,6BAHA,6BkB39FA,sCClBM,sCnB8+FN,sCmBx+FI,iBAAA,KACA,aAAA,KDcJ,oBC9DE,MAAA,KACA,iBAAA,KpB0hGD,aoBvhGC,MAAA,KnBmiGA,iBAAkB,QmBjiGhB,aAAA,QpB2hGH,mBoBzhGO,mBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpB0hGH,mBoBvhGC,MAAA,KnBmiGA,iBAAkB,QAClB,aAAc,QmB/hGR,oBADJ,oBpB0hGH,mCoBvhGG,MAAA,KnBmiGF,iBAAkB,QAClB,aAAc,QmB/hGN,0BnBqiGV,0BAHA,0BmBniGM,0BnBqiGN,0BAHA,0BDFC,yCoBjiGK,yCnBqiGN,yCmBhiGE,MAAA,KnBwiGA,iBAAkB,QAClB,aAAc,QmBjiGZ,oBpByhGH,oBoBzhGG,mCnBsiGF,iBAAkB,KmBliGV,4BnBuiGV,4BAHA,4BDHC,6BCOD,6BAHA,6BkBjhGA,sCCrBM,sCnBuiGN,sCmBjiGI,iBAAA,QACA,aAAA,QDkBJ,oBClEE,MAAA,QACA,iBAAA,KpBmlGD,aoBhlGC,MAAA,KnB4lGA,iBAAkB,QmB1lGhB,aAAA,QpBolGH,mBoBllGO,mBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpBmlGH,mBoBhlGC,MAAA,KnB4lGA,iBAAkB,QAClB,aAAc,QmBxlGR,oBADJ,oBpBmlGH,mCoBhlGG,MAAA,KnB4lGF,iBAAkB,QAClB,aAAc,QmBxlGN,0BnB8lGV,0BAHA,0BmB5lGM,0BnB8lGN,0BAHA,0BDFC,yCoB1lGK,yCnB8lGN,yCmBzlGE,MAAA,KnBimGA,iBAAkB,QAClB,aAAc,QmB1lGZ,oBpBklGH,oBoBllGG,mCnB+lGF,iBAAkB,KmB3lGV,4BnBgmGV,4BAHA,4BDHC,6BCOD,6BAHA,6BkBtkGA,sCCzBM,sCnBgmGN,sCmB1lGI,iBAAA,QACA,aAAA,QDsBJ,oBCtEE,MAAA,QACA,iBAAA,KpB4oGD,UoBzoGC,MAAA,KnBqpGA,iBAAkB,QmBnpGhB,aAAA,QpB6oGH,gBoB3oGO,gBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpB4oGH,gBoBzoGC,MAAA,KnBqpGA,iBAAkB,QAClB,aAAc,QmBjpGR,iBADJ,iBpB4oGH,gCoBzoGG,MAAA,KnBqpGF,iBAAkB,QAClB,aAAc,QmBjpGN,uBnBupGV,uBAHA,uBmBrpGM,uBnBupGN,uBAHA,uBDFC,sCoBnpGK,sCnBupGN,sCmBlpGE,MAAA,KnB0pGA,iBAAkB,QAClB,aAAc,QmBnpGZ,iBpB2oGH,iBoB3oGG,gCnBwpGF,iBAAkB,KmBppGV,yBnBypGV,yBAHA,yBDHC,0BCOD,0BAHA,0BkB3nGA,mCC7BM,mCnBypGN,mCmBnpGI,iBAAA,QACA,aAAA,QD0BJ,iBC1EE,MAAA,QACA,iBAAA,KpBqsGD,aoBlsGC,MAAA,KnB8sGA,iBAAkB,QmB5sGhB,aAAA,QpBssGH,mBoBpsGO,mBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpBqsGH,mBoBlsGC,MAAA,KnB8sGA,iBAAkB,QAClB,aAAc,QmB1sGR,oBADJ,oBpBqsGH,mCoBlsGG,MAAA,KnB8sGF,iBAAkB,QAClB,aAAc,QmB1sGN,0BnBgtGV,0BAHA,0BmB9sGM,0BnBgtGN,0BAHA,0BDFC,yCoB5sGK,yCnBgtGN,yCmB3sGE,MAAA,KnBmtGA,iBAAkB,QAClB,aAAc,QmB5sGZ,oBpBosGH,oBoBpsGG,mCnBitGF,iBAAkB,KmB7sGV,4BnBktGV,4BAHA,4BDHC,6BCOD,6BAHA,6BkBhrGA,sCCjCM,sCnBktGN,sCmB5sGI,iBAAA,QACA,aAAA,QD8BJ,oBC9EE,MAAA,QACA,iBAAA,KpB8vGD,YoB3vGC,MAAA,KnBuwGA,iBAAkB,QmBrwGhB,aAAA,QpB+vGH,kBoB7vGO,kBAEN,MAAA,KACE,iBAAA,QACA,aAAA,QpB8vGH,kBoB3vGC,MAAA,KnBuwGA,iBAAkB,QAClB,aAAc,QmBnwGR,mBADJ,mBpB8vGH,kCoB3vGG,MAAA,KnBuwGF,iBAAkB,QAClB,aAAc,QmBnwGN,yBnBywGV,yBAHA,yBmBvwGM,yBnBywGN,yBAHA,yBDFC,wCoBrwGK,wCnBywGN,wCmBpwGE,MAAA,KnB4wGA,iBAAkB,QAClB,aAAc,QmBrwGZ,mBpB6vGH,mBoB7vGG,kCnB0wGF,iBAAkB,KmBtwGV,2BnB2wGV,2BAHA,2BDHC,4BCOD,4BAHA,4BkBruGA,qCCrCM,qCnB2wGN,qCmBrwGI,iBAAA,QACA,aAAA,QDuCJ,mBACE,MAAA,QACA,iBAAA,KnB+tGD,UmB5tGC,YAAA,IlBwuGA,MAAO,QACP,cAAe,EAEjB,UGzwGE,iBemCE,iBflCM,oBJkwGT,6BmB7tGC,iBAAA,YlByuGA,mBAAoB,KACZ,WAAY,KkBtuGlB,UAEF,iBAAA,gBnB6tGD,gBmB3tGG,aAAA,YnBiuGH,gBmB/tGG,gBAIA,MAAA,QlBuuGF,gBAAiB,UACjB,iBAAkB,YDNnB,0BmBhuGK,0BAUN,mCATM,mClB2uGJ,MAAO,KmB1yGP,gBAAA,KAGA,mBADA,QpBmyGD,QAAA,KAAA,KmBztGC,UAAW,KlBquGX,YAAa,UmBjzGb,cAAA,IAGA,mBADA,QpB0yGD,QAAA,IAAA,KmB5tGC,UAAW,KlBwuGX,YAAa,ImBxzGb,cAAA,IAGA,mBADA,QpBizGD,QAAA,IAAA,ImB3tGC,UAAW,KACX,YAAA,IACA,cAAA,IAIF,WACE,QAAA,MnB2tGD,MAAA,KCYD,sBACE,WAAY,IqBz3GZ,6BADF,4BtBk3GC,6BI7rGC,MAAA,KAEQ,MJisGT,QAAA,EsBr3GC,mBAAA,QAAA,KAAA,OACE,cAAA,QAAA,KAAA,OtBu3GH,WAAA,QAAA,KAAA,OsBl3GC,StBq3GD,QAAA,EsBn3Ga,UtBs3Gb,QAAA,KsBr3Ga,atBw3Gb,QAAA,MsBv3Ga,etB03Gb,QAAA,UsBt3GC,kBACA,QAAA,gBlBwKA,YACQ,SAAA,SAAA,OAAA,EAOR,SAAA,OACQ,mCAAA,KAAA,8BAAA,KAGR,2BAAA,KACQ,4BAAA,KAAA,uBAAA,KJ2sGT,oBAAA,KuBr5GC,4BAA6B,OAAQ,WACrC,uBAAA,OAAA,WACA,oBAAA,OAAA,WAEA,OACA,QAAA,aACA,MAAA,EACA,OAAA,EACA,YAAA,IACA,eAAA,OvBu5GD,WAAA,IAAA,OuBn5GC,WAAY,IAAI,QtBk6GhB,aAAc,IAAI,MAAM,YsBh6GxB,YAAA,IAAA,MAAA,YAKA,UADF,QvBo5GC,SAAA,SuB94GC,uBACA,QAAA,EAEA,eACA,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,IAAA,EACA,OAAA,IAAA,EAAA,EACA,UAAA,KACA,WAAA,KACA,WAAA,KnBsBA,iBAAA,KACQ,wBAAA,YmBrBR,gBAAA,YtB+5GA,OsB/5GA,IAAA,MAAA,KvBk5GD,OAAA,IAAA,MAAA,gBuB74GC,cAAA,IACE,mBAAA,EAAA,IAAA,KAAA,iBACA,WAAA,EAAA,IAAA,KAAA,iBAzBJ,0BCzBE,MAAA,EACA,KAAA,KAEA,wBxBo8GD,OAAA,IuB96GC,OAAQ,IAAI,EAmCV,SAAA,OACA,iBAAA,QAEA,oBACA,QAAA,MACA,QAAA,IAAA,KACA,MAAA,KvB84GH,YAAA,IuBx4GC,YAAA,WtBw5GA,MAAO,KsBt5GL,YAAA,OvB44GH,0BuB14GG,0BAMF,MAAA,QtBo5GA,gBAAiB,KACjB,iBAAkB,QsBj5GhB,yBAEA,+BADA,+BvBu4GH,MAAA,KuB73GC,gBAAA,KtB64GA,iBAAkB,QAClB,QAAS,EDZV,2BuB33GC,iCAAA,iCAEE,MAAA,KEzGF,iCF2GE,iCAEA,gBAAA,KvB63GH,OAAA,YuBx3GC,iBAAkB,YAGhB,iBAAA,KvBw3GH,OAAA,0DuBn3GG,qBvBs3GH,QAAA,MuB72GC,QACA,QAAA,EAQF,qBACE,MAAA,EACA,KAAA,KAIF,oBACE,MAAA,KACA,KAAA,EAEA,iBACA,QAAA,MACA,QAAA,IAAA,KvBw2GD,UAAA,KuBp2GC,YAAa,WACb,MAAA,KACA,YAAA,OAEA,mBACA,SAAA,MACA,IAAA,EvBs2GD,MAAA,EuBl2GC,OAAQ,EACR,KAAA,EACA,QAAA,IAQF,2BtB42GE,MAAO,EsBx2GL,KAAA,KAEA,eACA,sCvB41GH,QAAA,GuBn2GC,WAAY,EtBm3GZ,cAAe,IAAI,OsBx2GjB,cAAA,IAAA,QAEA,uBvB41GH,8CuBv0GC,IAAK,KAXL,OAAA,KApEA,cAAA,IvB25GC,yBuBv1GD,6BA1DA,MAAA,EACA,KAAA,KvBq5GD,kC0BpiHG,MAAO,KzBojHP,KAAM,GyBhjHR,W1BsiHD,oB0B1iHC,SAAU,SzB0jHV,QAAS,ayBpjHP,eAAA,OAGA,yB1BsiHH,gBCgBC,SAAU,SACV,MAAO,KyB7iHT,gC1BsiHC,gCCYD,+BAFA,+ByBhjHA,uBANM,uBzBujHN,sBAFA,sBAQE,QAAS,EyBljHP,qB1BuiHH,2B0BliHD,2BACE,iC1BoiHD,YAAA,KCgBD,aACE,YAAa,KDZd,kB0B1iHD,wBAAA,0BzB2jHE,MAAO,KDZR,kB0B/hHD,wBACE,0B1BiiHD,YAAA,I0B5hHC,yE1B+hHD,cAAA,E2BhlHC,4BACG,YAAA,EDsDL,mEzB6iHE,wBAAyB,E0B5lHzB,2BAAA,E3BilHD,6C0B5hHD,8CACE,uBAAA,E1B8hHD,0BAAA,E0B3hHC,sB1B8hHD,MAAA,KCgBD,8D0B/mHE,cAAA,E3BomHD,mE0B3hHD,oECjEE,wBAAA,EACG,2BAAA,EDqEL,oEzB0iHE,uBAAwB,EyBxiHxB,0BAAA,EAiBF,mCACE,iCACA,QAAA,EAEF,iCACE,cAAA,IACA,aAAA,IAKF,oCtB/CE,cAAA,KACQ,aAAA,KsBkDR,iCtBnDA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBsByDV,0CACE,mBAAA,K1BugHD,WAAA,K0BngHC,YACA,YAAA,EAGF,eACE,aAAA,IAAA,IAAA,E1BqgHD,oBAAA,ECgBD,uBACE,aAAc,EAAE,IAAI,IyB1gHlB,yBACA,+BACA,oC1B+/GH,QAAA,M0BtgHC,MAAO,KAcH,MAAA,K1B2/GL,UAAA,KCgBD,oCACE,MAAO,KyBpgHL,8BACA,oC1By/GH,oC0Bp/GC,0CACE,WAAA,K1Bs/GH,YAAA,E2B/pHC,4DACC,cAAA,EAQA,sD3B4pHF,uBAAA,I0Bt/GC,wBAAA,IC/KA,2BAAA,EACC,0BAAA,EAQA,sD3BkqHF,uBAAA,E0Bv/GC,wBAAyB,EACzB,2BAAA,I1By/GD,0BAAA,ICgBD,uE0BtrHE,cAAA,E3B2qHD,4E0Bt/GD,6EC7LE,2BAAA,EACC,0BAAA,EDoMH,6EACE,uBAAA,EACA,wBAAA,EAEA,qB1Bo/GD,QAAA,M0Bx/GC,MAAO,KzBwgHP,aAAc,MyBjgHZ,gBAAA,SAEA,0B1Bq/GH,gC0B9/GC,QAAS,WAYP,MAAA,K1Bq/GH,MAAA,G0Bj/GG,qC1Bo/GH,MAAA,KCgBD,+CACE,KAAM,KyB7+GF,gDAFA,6C1Bs+GL,2D0Br+GK,wDEzOJ,SAAU,SACV,KAAA,cACA,eAAA,K5BitHD,a4B7sHC,SAAA,SACE,QAAA,MACA,gBAAA,S5BgtHH,0B4BxtHC,MAAO,KAeL,cAAA,EACA,aAAA,EAOA,2BACA,SAAA,S5BusHH,QAAA,E4BrsHG,MAAA,KACE,MAAA,K5BusHL,cAAA,ECgBD,iCACE,QAAS,EiBnrHT,8BACA,mCACA,sCACA,OAAA,KlBwqHD,QAAA,KAAA,KkBtqHC,UAAA,KjBsrHA,YAAa,UACb,cAAe,IiBrrHb,oClB0qHH,yCkBvqHC,4CjBurHA,OAAQ,KACR,YAAa,KDTd,8C4B/sHD,mDAAA,sD3B0tHA,sCACA,2CiBzrHI,8CjB8rHF,OAAQ,KiB1sHR,8BACA,mCACA,sCACA,OAAA,KlB+rHD,QAAA,IAAA,KkB7rHC,UAAA,KjB6sHA,YAAa,IACb,cAAe,IiB5sHb,oClBisHH,yCkB9rHC,4CjB8sHA,OAAQ,KACR,YAAa,KDTd,8C4B7tHD,mDAAA,sD3BwuHA,sCACA,2CiBhtHI,8CjBqtHF,OAAQ,K2BzuHR,2B5B6tHD,mB4B7tHC,iB3B8uHA,QAAS,W2BzuHX,8D5B6tHC,sD4B7tHD,oDAEE,cAAA,EAEA,mB5B+tHD,iB4B1tHC,MAAO,GACP,YAAA,OACA,eAAA,OAEA,mBACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,K5B4tHD,WAAA,O4BztHC,iBAAA,KACE,OAAA,IAAA,MAAA,KACA,cAAA,I5B4tHH,4B4BztHC,QAAA,IAAA,KACE,UAAA,KACA,cAAA,I5B4tHH,4B4B/uHC,QAAS,KAAK,K3B+vHd,UAAW,K2BruHT,cAAA,IAKJ,wCAAA,qC3BquHE,WAAY,EAEd,uCACA,+BACA,kC0B70HE,6CACG,8CC4GL,6D5BqtHC,wE4BptHC,wBAAA,E5ButHD,2BAAA,ECgBD,+BACE,aAAc,EAEhB,sCACA,8B2BhuHA,+D5BstHC,oDCWD,iC0Bl1HE,4CACG,6CCiHH,uBAAA,E5BwtHD,0BAAA,E4BltHC,8BAGA,YAAA,E5BotHD,iB4BxtHC,SAAU,SAUR,UAAA,E5BitHH,YAAA,O4B/sHK,sB5BktHL,SAAA,SCgBD,2BACE,YAAa,K2BxtHb,6BAAA,4B5B4sHD,4B4BzsHK,QAAA,EAGJ,kCAAA,wCAGI,aAAA,K5B4sHL,iC6B12HD,uCACE,QAAA,EACA,YAAA,K7B62HD,K6B/2HC,aAAc,EAOZ,cAAA,EACA,WAAA,KARJ,QAWM,SAAA,SACA,QAAA,M7B42HL,U6B12HK,SAAA,S5B03HJ,QAAS,M4Bx3HH,QAAA,KAAA,KAMJ,gB7Bu2HH,gB6Bt2HK,gBAAA,K7By2HL,iBAAA,KCgBD,mB4Br3HQ,MAAA,KAGA,yBADA,yB7B02HP,MAAA,K6Bl2HG,gBAAA,K5Bk3HF,OAAQ,YACR,iBAAkB,Y4B/2Hd,aAzCN,mB7B64HC,mBwBh5HC,iBAAA,KACA,aAAA,QAEA,kBxBm5HD,OAAA,I6Bn5HC,OAAQ,IAAI,EA0DV,SAAA,O7B41HH,iBAAA,Q6Bl1HC,c7Bq1HD,UAAA,K6Bn1HG,UAEA,cAAA,IAAA,MAAA,KALJ,aASM,MAAA,KACA,cAAA,KAEA,e7Bo1HL,aAAA,I6Bn1HK,YAAA,WACE,OAAA,IAAA,MAAA,Y7Bq1HP,cAAA,IAAA,IAAA,EAAA,ECgBD,qBACE,aAAc,KAAK,KAAK,K4B51HlB,sBAEA,4BADA,4BAEA,MAAA,K7Bi1HP,OAAA,Q6B50HC,iBAAA,KAqDA,OAAA,IAAA,MAAA,KA8BA,oBAAA,YAnFA,wBAwDE,MAAA,K7B2xHH,cAAA,E6BzxHK,2BACA,MAAA,KA3DJ,6BAgEE,cAAA,IACA,WAAA,OAYJ,iDA0DE,IAAK,KAjED,KAAA,K7B0xHH,yB6BztHD,2BA9DM,QAAA,W7B0xHL,MAAA,G6Bn2HD,6BAuFE,cAAA,GAvFF,6B5Bw3HA,aAAc,EACd,cAAe,IDZhB,kC6BtuHD,wCA3BA,wCATM,OAAA,IAAA,MAAA,K7B+wHH,yB6B3uHD,6B5B2vHE,cAAe,IAAI,MAAM,KACzB,cAAe,IAAI,IAAI,EAAE,EDZ1B,kC6B92HD,wC7B+2HD,wC6B72HG,oBAAA,MAIE,c7B+2HL,MAAA,K6B52HK,gB7B+2HL,cAAA,ICgBD,iBACE,YAAa,I4Bv3HP,uBAQR,6B7Bo2HC,6B6Bl2HG,MAAA,K7Bq2HH,iBAAA,Q6Bn2HK,gBACA,MAAA,KAYN,mBACE,WAAA,I7B41HD,YAAA,E6Bz1HG,e7B41HH,MAAA,K6B11HK,kBACA,MAAA,KAPN,oBAYI,cAAA,IACA,WAAA,OAYJ,wCA0DE,IAAK,KAjED,KAAA,K7B21HH,yB6B1xHD,kBA9DM,QAAA,W7B21HL,MAAA,G6Bl1HD,oBACA,cAAA,GAIE,oBACA,cAAA,EANJ,yB5B02HE,aAAc,EACd,cAAe,IDZhB,8B6B1yHD,oCA3BA,oCATM,OAAA,IAAA,MAAA,K7Bm1HH,yB6B/yHD,yB5B+zHE,cAAe,IAAI,MAAM,KACzB,cAAe,IAAI,IAAI,EAAE,EDZ1B,8B6Bx0HD,oC7By0HD,oC6Bv0HG,oBAAA,MAGA,uB7B00HH,QAAA,K6B/zHC,qBF3OA,QAAA,M3B+iID,yB8BxiIC,WAAY,KACZ,uBAAA,EACA,wBAAA,EAEA,Q9B0iID,SAAA,S8BliIC,WAAY,KA8nBZ,cAAe,KAhoBb,OAAA,IAAA,MAAA,Y9ByiIH,yB8BzhIC,QAgnBE,cAAe,K9B86GlB,yB8BjhIC,eACA,MAAA,MAGA,iBACA,cAAA,KAAA,aAAA,KAEA,WAAA,Q9BkhID,2BAAA,M8BhhIC,WAAA,IAAA,MAAA,YACE,mBAAA,MAAA,EAAA,IAAA,EAAA,qB9BkhIH,WAAA,MAAA,EAAA,IAAA,EAAA,qB8Bz7GD,oBArlBI,WAAA,KAEA,yBAAA,iB9BkhID,MAAA,K8BhhIC,WAAA,EACE,mBAAA,KACA,WAAA,KAEA,0B9BkhIH,QAAA,gB8B/gIC,OAAA,eACE,eAAA,E9BihIH,SAAA,kBCkBD,oBACE,WAAY,QDZf,sC8B/gIK,mC9B8gIH,oC8BzgIC,cAAe,E7B4hIf,aAAc,G6Bj+GlB,sCAnjBE,mC7ByhIA,WAAY,MDdX,4D8BngID,sC9BogID,mCCkBG,WAAY,O6B3gId,kCANE,gC9BsgIH,4B8BvgIG,0BAuiBF,aAAc,M7Bm/Gd,YAAa,MAEf,yBDZC,kC8B3gIK,gC9B0gIH,4B8B3gIG,0BAcF,aAAc,EAChB,YAAA,GAMF,mBA8gBE,QAAS,KAhhBP,aAAA,EAAA,EAAA,I9BkgIH,yB8B7/HC,mB7B+gIE,cAAe,G6B1gIjB,qBADA,kB9BggID,SAAA,M8Bz/HC,MAAO,EAggBP,KAAM,E7B4gHN,QAAS,KDdR,yB8B7/HD,qB9B8/HD,kB8B7/HC,cAAA,GAGF,kBACE,IAAA,EACA,aAAA,EAAA,EAAA,I9BigID,qB8B1/HC,OAAQ,EACR,cAAA,EACA,aAAA,IAAA,EAAA,EAEA,cACA,MAAA,K9B4/HD,OAAA,K8B1/HC,QAAA,KAAA,K7B4gIA,UAAW,K6B1gIT,YAAA,KAIA,oBAbJ,oB9BwgIC,gBAAA,K8Bv/HG,kB7B0gIF,QAAS,MDdR,yBACF,iC8Bh/HC,uCACA,YAAA,OAGA,eC9LA,SAAA,SACA,MAAA,MD+LA,QAAA,IAAA,KACA,WAAA,IACA,aAAA,KACA,cAAA,I9Bm/HD,iBAAA,Y8B/+HC,iBAAA,KACE,OAAA,IAAA,MAAA,Y9Bi/HH,cAAA,I8B5+HG,qBACA,QAAA,EAEA,yB9B++HH,QAAA,M8BrgIC,MAAO,KAyBL,OAAA,I9B++HH,cAAA,I8BpjHD,mCAvbI,WAAA,I9Bg/HH,yB8Bt+HC,eACA,QAAA,MAGE,YACA,OAAA,MAAA,M9By+HH,iB8B58HC,YAAA,KA2YA,eAAgB,KAjaZ,YAAA,KAEA,yBACA,iCACA,SAAA,OACA,MAAA,KACA,MAAA,KAAA,WAAA,E9Bs+HH,iBAAA,Y8B3kHC,OAAQ,E7B8lHR,mBAAoB,K6Bt/HhB,WAAA,KAGA,kDAqZN,sC9BklHC,QAAA,IAAA,KAAA,IAAA,KCmBD,sC6Bv/HQ,YAAA,KAmBR,4C9Bs9HD,4C8BvlHG,iBAAkB,M9B4lHnB,yB8B5lHD,YAtYI,MAAA,K9Bq+HH,OAAA,E8Bn+HK,eACA,MAAA,K9Bu+HP,iB8B39HG,YAAa,KACf,eAAA,MAGA,aACA,QAAA,KAAA,K1B9NA,WAAA,IACQ,aAAA,M2B/DR,cAAA,IACA,YAAA,M/B4vID,WAAA,IAAA,MAAA,YiBtuHC,cAAe,IAAI,MAAM,YAwEzB,mBAAoB,MAAM,EAAE,IAAI,EAAE,qBAAyB,EAAE,IAAI,EAAE,qBAtI/D,WAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,EAAA,IAAA,EAAA,qBAEA,yBjBwyHH,yBiBpqHC,QAAS,aA/HP,cAAA,EACA,eAAA,OjBuyHH,2BiBzqHC,QAAS,aAxHP,MAAA,KjBoyHH,eAAA,OiBhyHG,kCACA,QAAA,aAmHJ,0BhBmsHE,QAAS,aACT,eAAgB,OgB5yHd,wCjB6xHH,6CiBrrHD,2CjBwrHC,MAAA,KiB5xHG,wCACA,MAAA,KAmGJ,4BhB+sHE,cAAe,EgB3yHb,eAAA,OAGA,uBADA,oBjB6xHH,QAAA,aiBnsHC,WAAY,EhBstHZ,cAAe,EgB5yHX,eAAA,OAsFN,6BAAA,0BAjFI,aAAA,EAiFJ,4CjB4sHC,sCiBvxHG,SAAA,SjB0xHH,YAAA,E8BngID,kDAmWE,IAAK,GAvWH,yBACE,yB9B8gIL,cAAA,I8B5/HD,oCAoVE,cAAe,GA1Vf,yBACA,aACA,MAAA,KACA,YAAA,E1BzPF,eAAA,EACQ,aAAA,EJmwIP,YAAA,EACF,OAAA,E8BngIG,mBAAoB,KACtB,WAAA,M9BugID,8B8BngIC,WAAY,EACZ,uBAAA,EHzUA,wBAAA,EAQA,mDACC,cAAA,E3By0IF,uBAAA,I8B//HC,wBAAyB,IChVzB,2BAAA,EACA,0BAAA,EDkVA,YCnVA,WAAA,IACA,cAAA,IDqVA,mBCtVA,WAAA,KACA,cAAA,KD+VF,mBChWE,WAAA,KACA,cAAA,KDuWF,aAsSE,WAAY,KA1SV,cAAA,KAEA,yB9B+/HD,aACF,MAAA,K8Bl+HG,aAAc,KAhBhB,YAAA,MACA,yBE5WA,aF8WE,MAAA,eAFF,cAKI,MAAA,gB9Bu/HH,aAAA,M8B7+HD,4BACA,aAAA,GADF,gBAKI,iBAAA,Q9Bg/HH,aAAA,QCmBD,8B6BhgIM,MAAA,KARN,oC9B0/HC,oC8B5+HG,MAAA,Q9B++HH,iBAAA,Y8B1+HK,6B9B6+HL,MAAA,KCmBD,iC6B5/HQ,MAAA,KAKF,uC9By+HL,uCCmBC,MAAO,KACP,iBAAkB,Y6Bz/HZ,sCAIF,4C9Bu+HL,4CCmBC,MAAO,KACP,iBAAkB,Q6Bv/HZ,wCAxCR,8C9BihIC,8C8Bn+HG,MAAA,K9Bs+HH,iBAAA,YCmBD,+B6Bt/HM,aAAA,KAGA,qCApDN,qC9B2hIC,iBAAA,KCmBD,yC6Bp/HI,iBAAA,KAOE,iCAAA,6B7Bk/HJ,aAAc,Q6B9+HR,oCAiCN,0C9B+7HD,0C8B3xHC,MAAO,KA7LC,iBAAA,QACA,yB7B8+HR,sD6B5+HU,MAAA,KAKF,4D9By9HP,4DCmBC,MAAO,KACP,iBAAkB,Y6Bz+HV,2DAIF,iE9Bu9HP,iECmBC,MAAO,KACP,iBAAkB,Q6Bv+HV,6D9B09HX,mEADE,mE8B1jIC,MAAO,KA8GP,iBAAA,aAEE,6B9Bi9HL,MAAA,K8B58HG,mC9B+8HH,MAAA,KCmBD,0B6B/9HM,MAAA,KAIA,gCAAA,gC7Bg+HJ,MAAO,K6Bt9HT,0CARQ,0CASN,mD9Bu8HD,mD8Bt8HC,MAAA,KAFF,gBAKI,iBAAA,K9B08HH,aAAA,QCmBD,8B6B19HM,MAAA,QARN,oC9Bo9HC,oC8Bt8HG,MAAA,K9By8HH,iBAAA,Y8Bp8HK,6B9Bu8HL,MAAA,QCmBD,iC6Bt9HQ,MAAA,QAKF,uC9Bm8HL,uCCmBC,MAAO,KACP,iBAAkB,Y6Bn9HZ,sCAIF,4C9Bi8HL,4CCmBC,MAAO,KACP,iBAAkB,Q6Bj9HZ,wCAxCR,8C9B2+HC,8C8B57HG,MAAA,K9B+7HH,iBAAA,YCmBD,+B6B/8HM,aAAA,KAGA,qCArDN,qC9Bq/HC,iBAAA,KCmBD,yC6B78HI,iBAAA,KAME,iCAAA,6B7B48HJ,aAAc,Q6Bx8HR,oCAuCN,0C9Bm5HD,0C8B33HC,MAAO,KAvDC,iBAAA,QAuDV,yBApDU,kE9Bs7HP,aAAA,Q8Bn7HO,0D9Bs7HP,iBAAA,QCmBD,sD6Bt8HU,MAAA,QAKF,4D9Bm7HP,4DCmBC,MAAO,KACP,iBAAkB,Y6Bn8HV,2DAIF,iE9Bi7HP,iECmBC,MAAO,KACP,iBAAkB,Q6Bj8HV,6D9Bo7HX,mEADE,mE8B1hIC,MAAO,KA+GP,iBAAA,aAEE,6B9Bg7HL,MAAA,Q8B36HG,mC9B86HH,MAAA,KCmBD,0B6B97HM,MAAA,QAIA,gCAAA,gC7B+7HJ,MAAO,KgCvkJT,0CH0oBQ,0CGzoBN,mDjCwjJD,mDiCvjJC,MAAA,KAEA,YACA,QAAA,IAAA,KjC2jJD,cAAA,KiChkJC,WAAY,KAQV,iBAAA,QjC2jJH,cAAA,IiCxjJK,eACA,QAAA,ajC4jJL,yBiCxkJC,QAAS,EAAE,IAkBT,MAAA,KjCyjJH,QAAA,SkC5kJC,oBACA,MAAA,KAEA,YlC+kJD,QAAA,akCnlJC,aAAc,EAOZ,OAAA,KAAA,ElC+kJH,cAAA,ICmBD,eiC/lJM,QAAA,OAEA,iBACA,oBACA,SAAA,SACA,MAAA,KACA,QAAA,IAAA,KACA,YAAA,KACA,YAAA,WlCglJL,MAAA,QkC9kJG,gBAAA,KjCimJF,iBAAkB,KiC9lJZ,OAAA,IAAA,MAAA,KPVH,6B3B2lJJ,gCkC7kJG,YAAA,EjCgmJF,uBAAwB,I0BvnJxB,0BAAA,I3BymJD,4BkCxkJG,+BjC2lJF,wBAAyB,IACzB,2BAA4B,IiCxlJxB,uBAFA,uBAGA,0BAFA,0BlC8kJL,QAAA,EkCtkJG,MAAA,QjCylJF,iBAAkB,KAClB,aAAc,KAEhB,sBiCvlJM,4BAFA,4BjC0lJN,yBiCvlJM,+BAFA,+BAGA,QAAA,ElC2kJL,MAAA,KkCloJC,OAAQ,QjCqpJR,iBAAkB,QAClB,aAAc,QiCnlJV,wBAEA,8BADA,8BjColJN,2BiCtlJM,iCjCulJN,iCDZC,MAAA,KkC/jJC,OAAQ,YjCklJR,iBAAkB,KkC7pJd,aAAA,KAEA,oBnC8oJL,uBmC5oJG,QAAA,KAAA,KlC+pJF,UAAW,K0B1pJX,YAAA,U3B4oJD,gCmC3oJG,mClC8pJF,uBAAwB,I0BvqJxB,0BAAA,I3BypJD,+BkC1kJD,kCjC6lJE,wBAAyB,IkC7qJrB,2BAAA,IAEA,oBnC8pJL,uBmC5pJG,QAAA,IAAA,KlC+qJF,UAAW,K0B1qJX,YAAA,I3B4pJD,gCmC3pJG,mClC8qJF,uBAAwB,I0BvrJxB,0BAAA,I3ByqJD,+BoC3qJD,kCACE,wBAAA,IACA,2BAAA,IAEA,OpC6qJD,aAAA,EoCjrJC,OAAQ,KAAK,EAOX,WAAA,OpC6qJH,WAAA,KCmBD,UmC7rJM,QAAA,OAEA,YACA,eACA,QAAA,apC8qJL,QAAA,IAAA,KoC5rJC,iBAAkB,KnC+sJlB,OAAQ,IAAI,MAAM,KmC5rJd,cAAA,KAnBN,kBpCisJC,kBCmBC,gBAAiB,KmCzrJb,iBAAA,KA3BN,eAAA,kBAkCM,MAAA,MAlCN,mBAAA,sBnC6tJE,MAAO,KmClrJH,mBAEA,yBADA,yBpCqqJL,sBqCltJC,MAAO,KACP,OAAA,YACA,iBAAA,KAEA,OACA,QAAA,OACA,QAAA,KAAA,KAAA,KACA,UAAA,IACA,YAAA,IACA,YAAA,EACA,MAAA,KrCotJD,WAAA,OqChtJG,YAAA,OpCmuJF,eAAgB,SoCjuJZ,cAAA,MrCotJL,cqCltJK,cAKJ,MAAA,KACE,gBAAA,KrC+sJH,OAAA,QqC1sJG,aACA,QAAA,KAOJ,YCtCE,SAAA,StC+uJD,IAAA,KCmBD,eqC7vJM,iBAAA,KALJ,2BD0CF,2BrC4sJC,iBAAA,QCmBD,eqCpwJM,iBAAA,QALJ,2BD8CF,2BrC+sJC,iBAAA,QCmBD,eqC3wJM,iBAAA,QALJ,2BDkDF,2BrCktJC,iBAAA,QCmBD,YqClxJM,iBAAA,QALJ,wBDsDF,wBrCqtJC,iBAAA,QCmBD,eqCzxJM,iBAAA,QALJ,2BD0DF,2BrCwtJC,iBAAA,QCmBD,cqChyJM,iBAAA,QCDJ,0BADF,0BAEE,iBAAA,QAEA,OACA,QAAA,aACA,UAAA,KACA,QAAA,IAAA,IACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OvCqxJD,YAAA,OuClxJC,eAAA,OACE,iBAAA,KvCoxJH,cAAA,KuC/wJG,aACA,QAAA,KAGF,YtCkyJA,SAAU,SsChyJR,IAAA,KAMA,0BvC4wJH,eCmBC,IAAK,EsC7xJD,QAAA,IAAA,IvCgxJL,cuC9wJK,cAKJ,MAAA,KtC4xJA,gBAAiB,KsC1xJf,OAAA,QvC4wJH,+BuCxwJC,4BACE,MAAA,QvC0wJH,iBAAA,KuCtwJG,wBvCywJH,MAAA,MuCrwJG,+BvCwwJH,aAAA,IwCj0JC,uBACA,YAAA,IAEA,WACA,YAAA,KxCo0JD,eAAA,KwCz0JC,cAAe,KvC41Jf,MAAO,QuCn1JL,iBAAA,KAIA,eAbJ,cAcI,MAAA,QxCo0JH,awCl1JC,cAAe,KAmBb,UAAA,KxCk0JH,YAAA,ICmBD,cuCh1JI,iBAAA,QAEA,sBxCi0JH,4BwC31JC,cAAe,KA8Bb,aAAA,KxCg0JH,cAAA,IwC7yJD,sBAfI,UAAA,KxCi0JD,oCwC9zJC,WvCi1JA,YAAa,KuC/0JX,eAAA,KxCi0JH,sBwCvzJD,4BvC00JE,cAAe,KuC90Jb,aAAA,KC5CJ,ezC42JD,cyC32JC,UAAA,MAGA,WACA,QAAA,MACA,QAAA,IACA,cAAA,KrCiLA,YAAA,WACK,iBAAA,KACG,OAAA,IAAA,MAAA,KJ8rJT,cAAA,IyCx3JC,mBAAoB,OAAO,IAAI,YxC24J1B,cAAe,OAAO,IAAI,YwC93J7B,WAAA,OAAA,IAAA,YAKF,iBzC22JD,eCmBC,aAAc,KACd,YAAa,KwCv3JX,mBA1BJ,kBzCk4JC,kByCv2JG,aAAA,QCzBJ,oBACE,QAAA,IACA,MAAA,KAEA,O1Cs4JD,QAAA,K0C14JC,cAAe,KAQb,OAAA,IAAA,MAAA,YAEA,cAAA,IAVJ,UAeI,WAAA,E1Ck4JH,MAAA,QCmBD,mByC/4JI,YAAA,IArBJ,SAyBI,U1C+3JH,cAAA,ECmBD,WyCx4JE,WAAA,IAFF,mBAAA,mBAMI,cAAA,KAEA,0BACA,0B1Cy3JH,SAAA,S0Cj3JC,IAAK,KCvDL,MAAA,MACA,MAAA,Q3C46JD,e0Ct3JC,MAAO,QClDL,iBAAA,Q3C26JH,aAAA,Q2Cx6JG,kB3C26JH,iBAAA,Q2Cn7JC,2BACA,MAAA,Q3Cu7JD,Y0C73JC,MAAO,QCtDL,iBAAA,Q3Cs7JH,aAAA,Q2Cn7JG,e3Cs7JH,iBAAA,Q2C97JC,wBACA,MAAA,Q3Ck8JD,e0Cp4JC,MAAO,QC1DL,iBAAA,Q3Ci8JH,aAAA,Q2C97JG,kB3Ci8JH,iBAAA,Q2Cz8JC,2BACA,MAAA,Q3C68JD,c0C34JC,MAAO,QC9DL,iBAAA,Q3C48JH,aAAA,Q2Cz8JG,iB3C48JH,iBAAA,Q4C78JC,0BAAQ,MAAA,QACR,wCAAQ,K5Cm9JP,oBAAA,KAAA,E4C/8JD,GACA,oBAAA,EAAA,GACA,mCAAQ,K5Cq9JP,oBAAA,KAAA,E4Cv9JD,GACA,oBAAA,EAAA,GACA,gCAAQ,K5Cq9JP,oBAAA,KAAA,E4C78JD,GACA,oBAAA,EAAA,GAGA,UACA,OAAA,KxCsCA,cAAA,KACQ,SAAA,OJ26JT,iBAAA,Q4C78JC,cAAe,IACf,mBAAA,MAAA,EAAA,IAAA,IAAA,eACA,WAAA,MAAA,EAAA,IAAA,IAAA,eAEA,cACA,MAAA,KACA,MAAA,EACA,OAAA,KACA,UAAA,KxCyBA,YAAA,KACQ,MAAA,KAyHR,WAAA,OACK,iBAAA,QACG,mBAAA,MAAA,EAAA,KAAA,EAAA,gBJ+zJT,WAAA,MAAA,EAAA,KAAA,EAAA,gB4C18JC,mBAAoB,MAAM,IAAI,K3Cq+JzB,cAAe,MAAM,IAAI,K4Cp+J5B,WAAA,MAAA,IAAA,KDEF,sBCAE,gCDAF,iBAAA,yK5C88JD,iBAAA,oK4Cv8JC,iBAAiB,iK3Cm+JjB,wBAAyB,KAAK,KG/gK9B,gBAAA,KAAA,KJy/JD,qBIv/JS,+BwCmDR,kBAAmB,qBAAqB,GAAG,OAAO,SErElD,aAAA,qBAAA,GAAA,OAAA,S9C4gKD,UAAA,qBAAA,GAAA,OAAA,S6Cz9JG,sBACA,iBAAA,Q7C69JH,wC4Cx8JC,iBAAkB,yKEzElB,iBAAA,oK9CohKD,iBAAA,iK6Cj+JG,mBACA,iBAAA,Q7Cq+JH,qC4C58JC,iBAAkB,yKE7ElB,iBAAA,oK9C4hKD,iBAAA,iK6Cz+JG,sBACA,iBAAA,Q7C6+JH,wC4Ch9JC,iBAAkB,yKEjFlB,iBAAA,oK9CoiKD,iBAAA,iK6Cj/JG,qBACA,iBAAA,Q7Cq/JH,uC+C5iKC,iBAAkB,yKAElB,iBAAA,oK/C6iKD,iBAAA,iK+C1iKG,O/C6iKH,WAAA,KC4BD,mB8CnkKE,WAAA,E/C4iKD,O+CxiKD,YACE,SAAA,O/C0iKD,KAAA,E+CtiKC,Y/CyiKD,MAAA,Q+CriKG,c/CwiKH,QAAA,MC4BD,4B8C9jKE,UAAA,KAGF,aAAA,mBAEE,aAAA,KAGF,YAAA,kB9C+jKE,cAAe,K8CxjKjB,YAHE,Y/CoiKD,a+ChiKC,QAAA,W/CmiKD,eAAA,I+C/hKC,c/CkiKD,eAAA,O+C7hKC,cACA,eAAA,OAMF,eACE,WAAA,EACA,cAAA,ICvDF,YAEE,aAAA,EACA,WAAA,KAQF,YACE,aAAA,EACA,cAAA,KAGA,iBACA,SAAA,SACA,QAAA,MhD6kKD,QAAA,KAAA,KgD1kKC,cAAA,KrB3BA,iBAAA,KACC,OAAA,IAAA,MAAA,KqB6BD,6BACE,uBAAA,IrBvBF,wBAAA,I3BsmKD,4BgDpkKC,cAAe,E/CgmKf,2BAA4B,I+C9lK5B,0BAAA,IAFF,kBAAA,uBAKI,MAAA,KAIF,2CAAA,gD/CgmKA,MAAO,K+C5lKL,wBAFA,wBhDykKH,6BgDxkKG,6BAKF,MAAO,KACP,gBAAA,KACA,iBAAA,QAKA,uB/C4lKA,MAAO,KACP,WAAY,K+CzlKV,0BhDmkKH,gCgDlkKG,gCALF,MAAA,K/CmmKA,OAAQ,YACR,iBAAkB,KDxBnB,mDgD5kKC,yDAAA,yD/CymKA,MAAO,QDxBR,gDgDhkKC,sDAAA,sD/C6lKA,MAAO,K+CzlKL,wBAEA,8BADA,8BhDmkKH,QAAA,EgDxkKC,MAAA,K/ComKA,iBAAkB,QAClB,aAAc,QAEhB,iDDpBC,wDCuBD,uDADA,uD+CzmKE,8DAYI,6D/C4lKN,uD+CxmKE,8D/C2mKF,6DAKE,MAAO,QDxBR,8CiD1qKG,oDADF,oDAEE,MAAA,QAEA,yBhDusKF,MAAO,QgDrsKH,iBAAA,QAFF,0BAAA,+BAKI,MAAA,QAGF,mDAAA,wDhDwsKJ,MAAO,QDtBR,gCiDhrKO,gCAGF,qCAFE,qChD2sKN,MAAO,QACP,iBAAkB,QAEpB,iCgDvsKQ,uCAFA,uChD0sKR,sCDtBC,4CiDnrKO,4CArBN,MAAA,KACE,iBAAA,QACA,aAAA,QAEA,sBhDouKF,MAAO,QgDluKH,iBAAA,QAFF,uBAAA,4BAKI,MAAA,QAGF,gDAAA,qDhDquKJ,MAAO,QDtBR,6BiD7sKO,6BAGF,kCAFE,kChDwuKN,MAAO,QACP,iBAAkB,QAEpB,8BgDpuKQ,oCAFA,oChDuuKR,mCDtBC,yCiDhtKO,yCArBN,MAAA,KACE,iBAAA,QACA,aAAA,QAEA,yBhDiwKF,MAAO,QgD/vKH,iBAAA,QAFF,0BAAA,+BAKI,MAAA,QAGF,mDAAA,wDhDkwKJ,MAAO,QDtBR,gCiD1uKO,gCAGF,qCAFE,qChDqwKN,MAAO,QACP,iBAAkB,QAEpB,iCgDjwKQ,uCAFA,uChDowKR,sCDtBC,4CiD7uKO,4CArBN,MAAA,KACE,iBAAA,QACA,aAAA,QAEA,wBhD8xKF,MAAO,QgD5xKH,iBAAA,QAFF,yBAAA,8BAKI,MAAA,QAGF,kDAAA,uDhD+xKJ,MAAO,QDtBR,+BiDvwKO,+BAGF,oCAFE,oChDkyKN,MAAO,QACP,iBAAkB,QAEpB,gCgD9xKQ,sCAFA,sChDiyKR,qCDtBC,2CiD1wKO,2CDkGN,MAAO,KACP,iBAAA,QACA,aAAA,QAEF,yBACE,WAAA,EACA,cAAA,IE1HF,sBACE,cAAA,EACA,YAAA,IAEA,O9C0DA,cAAA,KACQ,iBAAA,KJ6uKT,OAAA,IAAA,MAAA,YkDnyKC,cAAe,IACf,mBAAA,EAAA,IAAA,IAAA,gBlDqyKD,WAAA,EAAA,IAAA,IAAA,gBkD/xKC,YACA,QAAA,KvBnBC,e3BuzKF,QAAA,KAAA,KkDtyKC,cAAe,IAAI,MAAM,YAMvB,uBAAA,IlDmyKH,wBAAA,IkD7xKC,0CACA,MAAA,QAEA,alDgyKD,WAAA,EkDpyKC,cAAe,EjDg0Kf,UAAW,KACX,MAAO,QDtBR,oBkD1xKC,sBjDkzKF,eiDxzKI,mBAKJ,qBAEE,MAAA,QvBvCA,cACC,QAAA,KAAA,K3Bs0KF,iBAAA,QkDrxKC,WAAY,IAAI,MAAM,KjDizKtB,2BAA4B,IiD9yK1B,0BAAA,IAHJ,mBAAA,mCAMM,cAAA,ElDwxKL,oCkDnxKG,oDjD+yKF,aAAc,IAAI,EiD7yKZ,cAAA,EvBtEL,4D3B61KF,4EkDjxKG,WAAA,EjD6yKF,uBAAwB,IiD3yKlB,wBAAA,IvBtEL,0D3B21KF,0EkD1yKC,cAAe,EvB1Df,2BAAA,IACC,0BAAA,IuB0FH,+EAEI,uBAAA,ElD8wKH,wBAAA,EkD1wKC,wDlD6wKD,iBAAA,EC4BD,0BACE,iBAAkB,EiDlyKpB,8BlD0wKC,ckD1wKD,gCjDuyKE,cAAe,EiDvyKjB,sCAQM,sBlDwwKL,wCC4BC,cAAe,K0Br5Kf,aAAA,KuByGF,wDlDqxKC,0BC4BC,uBAAwB,IACxB,wBAAyB,IiDlzK3B,yFAoBQ,yFlDwwKP,2DkDzwKO,2DjDqyKN,uBAAwB,IACxB,wBAAyB,IAK3B,wGiD9zKA,wGjD4zKA,wGDtBC,wGCuBD,0EiD7zKA,0EjD2zKA,0EiDnyKU,0EjD2yKR,uBAAwB,IAK1B,uGiDx0KA,uGjDs0KA,uGDtBC,uGCuBD,yEiDv0KA,yEjDq0KA,yEiDzyKU,yEvB7HR,wBAAA,IuBiGF,sDlDqzKC,yBC4BC,2BAA4B,IAC5B,0BAA2B,IiDxyKrB,qFA1CR,qFAyCQ,wDlDmxKP,wDC4BC,2BAA4B,IAC5B,0BAA2B,IAG7B,oGDtBC,oGCwBD,oGiD91KA,oGjD21KA,uEiD7yKU,uEjD+yKV,uEiD71KA,uEjDm2KE,0BAA2B,IAG7B,mGDtBC,mGCwBD,mGiDx2KA,mGjDq2KA,sEiDnzKU,sEjDqzKV,sEiDv2KA,sEjD62KE,2BAA4B,IiDlzK1B,0BlD2xKH,qCkDt1KD,0BAAA,qCA+DI,WAAA,IAAA,MAAA,KA/DJ,kDAAA,kDAmEI,WAAA,EAnEJ,uBAAA,yCjD23KE,OAAQ,EiDjzKA,+CjDqzKV,+CiD/3KA,+CjDi4KA,+CAEA,+CANA,+CDjBC,iECoBD,iEiDh4KA,iEjDk4KA,iEAEA,iEANA,iEAWE,YAAa,EiD3zKL,8CjD+zKV,8CiD74KA,8CjD+4KA,8CAEA,8CANA,8CDjBC,gECoBD,gEiD94KA,gEjDg5KA,gEAEA,gEANA,gEAWE,aAAc,EAIhB,+CiD35KA,+CjDy5KA,+CiDl0KU,+CjDq0KV,iEiD55KA,iEjD05KA,iEDtBC,iEC6BC,cAAe,EAEjB,8CiDn0KU,8CjDq0KV,8CiDr6KA,8CjDo6KA,gEDtBC,gECwBD,gEiDh0KI,gEACA,cAAA,EAUJ,yBACE,cAAA,ElDmyKD,OAAA,EkD/xKG,aACA,cAAA,KANJ,oBASM,cAAA,ElDkyKL,cAAA,IkD7xKG,2BlDgyKH,WAAA,IC4BD,4BiDxzKM,cAAA,EAKF,wDAvBJ,wDlDqzKC,WAAA,IAAA,MAAA,KkD5xKK,2BlD+xKL,WAAA,EmDlhLC,uDnDqhLD,cAAA,IAAA,MAAA,KmDlhLG,eACA,aAAA,KnDshLH,8BmDxhLC,MAAA,KAMI,iBAAA,QnDqhLL,aAAA,KmDlhLK,0DACA,iBAAA,KAGJ,qCAEI,MAAA,QnDmhLL,iBAAA,KmDpiLC,yDnDuiLD,oBAAA,KmDpiLG,eACA,aAAA,QnDwiLH,8BmD1iLC,MAAA,KAMI,iBAAA,QnDuiLL,aAAA,QmDpiLK,0DACA,iBAAA,QAGJ,qCAEI,MAAA,QnDqiLL,iBAAA,KmDtjLC,yDnDyjLD,oBAAA,QmDtjLG,eACA,aAAA,QnD0jLH,8BmD5jLC,MAAA,QAMI,iBAAA,QnDyjLL,aAAA,QmDtjLK,0DACA,iBAAA,QAGJ,qCAEI,MAAA,QnDujLL,iBAAA,QmDxkLC,yDnD2kLD,oBAAA,QmDxkLG,YACA,aAAA,QnD4kLH,2BmD9kLC,MAAA,QAMI,iBAAA,QnD2kLL,aAAA,QmDxkLK,uDACA,iBAAA,QAGJ,kCAEI,MAAA,QnDykLL,iBAAA,QmD1lLC,sDnD6lLD,oBAAA,QmD1lLG,eACA,aAAA,QnD8lLH,8BmDhmLC,MAAA,QAMI,iBAAA,QnD6lLL,aAAA,QmD1lLK,0DACA,iBAAA,QAGJ,qCAEI,MAAA,QnD2lLL,iBAAA,QmD5mLC,yDnD+mLD,oBAAA,QmD5mLG,cACA,aAAA,QnDgnLH,6BmDlnLC,MAAA,QAMI,iBAAA,QnD+mLL,aAAA,QmD5mLK,yDACA,iBAAA,QAGJ,oCAEI,MAAA,QnD6mLL,iBAAA,QoD5nLC,wDACA,oBAAA,QAEA,kBACA,SAAA,SpD+nLD,QAAA,MoDpoLC,OAAQ,EnDgqLR,QAAS,EACT,SAAU,OAEZ,yCmDtpLI,wBADA,yBAEA,yBACA,wBACA,SAAA,SACA,IAAA,EACA,OAAA,EpD+nLH,KAAA,EoD1nLC,MAAO,KACP,OAAA,KpD4nLD,OAAA,EoDvnLC,wBpD0nLD,eAAA,OqDppLC,uBACA,eAAA,IAEA,MACA,WAAA,KACA,QAAA,KjDwDA,cAAA,KACQ,iBAAA,QJgmLT,OAAA,IAAA,MAAA,QqD/pLC,cAAe,IASb,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACA,WAAA,MAAA,EAAA,IAAA,IAAA,gBAKJ,iBACE,aAAA,KACA,aAAA,gBAEF,SACE,QAAA,KACA,cAAA,ICtBF,SACE,QAAA,IACA,cAAA,IAEA,OACA,MAAA,MACA,UAAA,KjCRA,YAAA,IAGA,YAAA,ErBqrLD,MAAA,KsD7qLC,YAAA,EAAA,IAAA,EAAA,KrDysLA,OAAQ,kBqDvsLN,QAAA,GjCbF,aiCeE,ajCZF,MAAA,KrB6rLD,gBAAA,KsDzqLC,OAAA,QACE,OAAA,kBACA,QAAA,GAEA,aACA,mBAAA,KtD2qLH,QAAA,EuDhsLC,OAAQ,QACR,WAAA,IvDksLD,OAAA,EuD7rLC,YACA,SAAA,OAEA,OACA,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EAIA,QAAA,KvD6rLD,QAAA,KuD1rLC,SAAA,OnD+GA,2BAAA,MACI,QAAA,EAEI,0BAkER,mBAAA,kBAAA,IAAA,SAEK,cAAA,aAAA,IAAA,SACG,WAAA,UAAA,IAAA,SJ6gLT,kBAAA,kBuDhsLC,cAAA,kBnD2GA,aAAA,kBACI,UAAA,kBAEI,wBJwlLT,kBAAA,euDpsLK,cAAe,eACnB,aAAA,eACA,UAAA,eAIF,mBACE,WAAA,OACA,WAAA,KvDqsLD,cuDhsLC,SAAU,SACV,MAAA,KACA,OAAA,KAEA,eACA,SAAA,SnDaA,iBAAA,KACQ,wBAAA,YmDZR,gBAAA,YtD4tLA,OsD5tLA,IAAA,MAAA,KAEA,OAAA,IAAA,MAAA,evDksLD,cAAA,IuD9rLC,QAAS,EACT,mBAAA,EAAA,IAAA,IAAA,eACA,WAAA,EAAA,IAAA,IAAA,eAEA,gBACA,SAAA,MACA,IAAA,EACA,MAAA,EvDgsLD,OAAA,EuD9rLC,KAAA,ElCrEA,QAAA,KAGA,iBAAA,KkCmEA,qBlCtEA,OAAA,iBAGA,QAAA,EkCwEF,mBACE,OAAA,kBACA,QAAA,GAIF,cACE,QAAA,KvDgsLD,cAAA,IAAA,MAAA,QuD3rLC,qBACA,WAAA,KAKF,aACE,OAAA,EACA,YAAA,WAIF,YACE,SAAA,SACA,QAAA,KvD0rLD,cuD5rLC,QAAS,KAQP,WAAA,MACA,WAAA,IAAA,MAAA,QATJ,wBAaI,cAAA,EvDsrLH,YAAA,IuDlrLG,mCvDqrLH,YAAA,KuD/qLC,oCACA,YAAA,EAEA,yBACA,SAAA,SvDkrLD,IAAA,QuDhqLC,MAAO,KAZP,OAAA,KACE,SAAA,OvDgrLD,yBuD7qLD,cnDvEA,MAAA,MACQ,OAAA,KAAA,KmD2ER,eAAY,mBAAA,EAAA,IAAA,KAAA,evD+qLX,WAAA,EAAA,IAAA,KAAA,euDzqLD,UAFA,MAAA,OvDirLD,yBwD/zLC,UACA,MAAA,OCNA,SAEA,SAAA,SACA,QAAA,KACA,QAAA,MACA,YAAA,iBAAA,UAAA,MAAA,WACA,UAAA,KACA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,ODHA,WAAA,OnCVA,aAAA,OAGA,UAAA,OrBs1LD,YAAA,OwD30LC,OAAA,iBnCdA,QAAA,ErB61LD,WAAA,KwD90LY,YAAmB,OAAA,kBxDk1L/B,QAAA,GwDj1LY,aAAmB,QAAA,IAAA,ExDq1L/B,WAAA,KwDp1LY,eAAmB,QAAA,EAAA,IxDw1L/B,YAAA,IwDv1LY,gBAAmB,QAAA,IAAA,ExD21L/B,WAAA,IwDt1LC,cACA,QAAA,EAAA,IACA,YAAA,KAEA,eACA,UAAA,MxDy1LD,QAAA,IAAA,IwDr1LC,MAAO,KACP,WAAA,OACA,iBAAA,KACA,cAAA,IAEA,exDu1LD,SAAA,SwDn1LC,MAAA,EACE,OAAA,EACA,aAAA,YACA,aAAA,MAEA,4BxDq1LH,OAAA,EwDn1LC,KAAA,IACE,YAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEA,iCxDq1LH,MAAA,IwDn1LC,OAAA,EACE,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEA,kCxDq1LH,OAAA,EwDn1LC,KAAA,IACE,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEA,8BxDq1LH,IAAA,IwDn1LC,KAAA,EACE,WAAA,KACA,aAAA,IAAA,IAAA,IAAA,EACA,mBAAA,KAEA,6BxDq1LH,IAAA,IwDn1LC,MAAA,EACE,WAAA,KACA,aAAA,IAAA,EAAA,IAAA,IACA,kBAAA,KAEA,+BxDq1LH,IAAA,EwDn1LC,KAAA,IACE,YAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEA,oCxDq1LH,IAAA,EwDn1LC,MAAA,IACE,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEA,qCxDq1LH,IAAA,E0Dl7LC,KAAM,IACN,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEA,SACA,SAAA,SACA,IAAA,EDXA,KAAA,EAEA,QAAA,KACA,QAAA,KACA,UAAA,MACA,QAAA,IACA,YAAA,iBAAA,UAAA,MAAA,WACA,UAAA,KACA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KCAA,eAAA,OAEA,WAAA,OACA,aAAA,OAAA,UAAA,OACA,YAAA,OACA,iBAAA,KACA,wBAAA,YtD8CA,gBAAA,YACQ,OAAA,IAAA,MAAA,KJk5LT,OAAA,IAAA,MAAA,e0D77LC,cAAA,IAAY,mBAAA,EAAA,IAAA,KAAA,e1Dg8Lb,WAAA,EAAA,IAAA,KAAA,e0D/7La,WAAA,KACZ,aAAY,WAAA,MACZ,eAAY,YAAA,KAGd,gBACE,WAAA,KAEA,cACA,YAAA,MAEA,e1Dq8LD,QAAA,IAAA,K0Dl8LC,OAAQ,EACR,UAAA,K1Do8LD,iBAAA,Q0D57LC,cAAA,IAAA,MAAA,QzDy9LA,cAAe,IAAI,IAAI,EAAE,EyDt9LvB,iBACA,QAAA,IAAA,KAEA,gBACA,sB1D87LH,SAAA,S0D37LC,QAAS,MACT,MAAA,E1D67LD,OAAA,E0D37LC,aAAc,YACd,aAAA,M1D87LD,gB0Dz7LC,aAAA,KAEE,sBACA,QAAA,GACA,aAAA,KAEA,oB1D27LH,OAAA,M0D17LG,KAAA,IACE,YAAA,MACA,iBAAA,KACA,iBAAA,gBACA,oBAAA,E1D67LL,0B0Dz7LC,OAAA,IACE,YAAA,MACA,QAAA,IACA,iBAAA,KACA,oBAAA,EAEA,sB1D27LH,IAAA,I0D17LG,KAAA,MACE,WAAA,MACA,mBAAA,KACA,mBAAA,gBACA,kBAAA,E1D67LL,4B0Dz7LC,OAAA,MACE,KAAA,IACA,QAAA,IACA,mBAAA,KACA,kBAAA,EAEA,uB1D27LH,IAAA,M0D17LG,KAAA,IACE,YAAA,MACA,iBAAA,EACA,oBAAA,KACA,oBAAA,gB1D67LL,6B0Dx7LC,IAAA,IACE,YAAA,MACA,QAAA,IACA,iBAAA,EACA,oBAAA,KAEA,qB1D07LH,IAAA,I0Dz7LG,MAAA,MACE,WAAA,MACA,mBAAA,EACA,kBAAA,KACA,kBAAA,gB1D47LL,2B2DpjMC,MAAO,IACP,OAAA,M3DsjMD,QAAA,I2DnjMC,mBAAoB,EACpB,kBAAA,KAEA,U3DqjMD,SAAA,S2DljMG,gBACA,SAAA,SvD6KF,MAAA,KACK,SAAA,OJ04LN,sB2D/jMC,SAAU,S1D4lMV,QAAS,K0D9kML,mBAAA,IAAA,YAAA,K3DqjML,cAAA,IAAA,YAAA,K2D3hMC,WAAA,IAAA,YAAA,KvDmKK,4BAFL,0BAGQ,YAAA,EA3JA,qDA+GR,sBAEQ,mBAAA,kBAAA,IAAA,YJ86LP,cAAA,aAAA,IAAA,Y2DzjMG,WAAA,UAAA,IAAA,YvDmHJ,4BAAA,OACQ,oBAAA,OuDjHF,oBAAA,O3D4jML,YAAA,OI58LD,mCHs+LA,2BGr+LQ,KAAA,EuD5GF,kBAAA,sB3D6jML,UAAA,sBC2BD,kCADA,2BG5+LA,KAAA,EACQ,kBAAA,uBuDtGF,UAAA,uBArCN,6B3DomMD,gC2DpmMC,iC1D+nME,KAAM,E0DllMN,kBAAA,mB3D4jMH,UAAA,oBAGA,wB2D5mMD,sBAAA,sBAsDI,QAAA,MAEA,wB3D0jMH,KAAA,E2DtjMG,sB3DyjMH,sB2DrnMC,SAAU,SA+DR,IAAA,E3DyjMH,MAAA,KC0BD,sB0D/kMI,KAAA,KAnEJ,sBAuEI,KAAA,MAvEJ,2BA0EI,4B3DwjMH,KAAA,E2D/iMC,6BACA,KAAA,MAEA,8BACA,KAAA,KtC3FA,kBsC6FA,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,I3DmjMD,UAAA,K2D9iMC,MAAA,KdnGE,WAAA,OACA,YAAA,EAAA,IAAA,IAAA,eACA,iBAAA,cAAA,OAAA,kBACA,QAAA,G7CqpMH,uB2DljMC,iBAAA,sEACE,iBAAA,iEACA,iBAAA,uFdxGA,iBAAA,kEACA,OAAA,+GACA,kBAAA,SACA,wBACA,MAAA,E7C6pMH,KAAA,K2DpjMC,iBAAA,sE1DglMA,iBAAiB,iE0D9kMf,iBAAA,uFACA,iBAAA,kEACA,OAAA,+GtCvHF,kBAAA,SsCyFF,wB3DslMC,wBC4BC,MAAO,KACP,gBAAiB,KACjB,OAAQ,kB0D7kMN,QAAA,EACA,QAAA,G3DwjMH,0C2DhmMD,2CA2CI,6BADA,6B1DklMF,SAAU,S0D7kMR,IAAA,IACA,QAAA,E3DqjMH,QAAA,a2DrmMC,WAAY,MAqDV,0CADA,6B3DsjMH,KAAA,I2D1mMC,YAAa,MA0DX,2CADA,6BAEA,MAAA,IACA,aAAA,MAME,6BADF,6B3DmjMH,MAAA,K2D9iMG,OAAA,KACE,YAAA,M3DgjML,YAAA,E2DriMC,oCACA,QAAA,QAEA,oCACA,QAAA,QAEA,qBACA,SAAA,SACA,OAAA,K3DwiMD,KAAA,I2DjjMC,QAAS,GAYP,MAAA,IACA,aAAA,EACA,YAAA,KACA,WAAA,OACA,WAAA,KAEA,wBACA,QAAA,aAWA,MAAA,KACA,OAAA,K3D8hMH,OAAA,I2D7jMC,YAAa,OAkCX,OAAA,QACA,iBAAA,OACA,iBAAA,cACA,OAAA,IAAA,MAAA,K3D8hMH,cAAA,K2DthMC,6BACA,MAAA,KACA,OAAA,KACA,OAAA,EACA,iBAAA,KAEA,kBACA,SAAA,SACA,MAAA,IACA,OAAA,K3DyhMD,KAAA,I2DxhMC,QAAA,GACE,YAAA,K3D0hMH,eAAA,K2Dj/LC,MAAO,KAhCP,WAAA,O1D8iMA,YAAa,EAAE,IAAI,IAAI,eAEzB,uB0D3iMM,YAAA,KAEA,oCACA,0C3DmhMH,2C2D3hMD,6BAAA,6BAYI,MAAA,K3DmhMH,OAAA,K2D/hMD,WAAA,M1D2jME,UAAW,KDxBZ,0C2D9gMD,6BACE,YAAA,MAEA,2C3DghMD,6B2D5gMD,aAAA,M3D+gMC,kBACF,MAAA,I4D7wMC,KAAA,I3DyyME,eAAgB,KAElB,qBACE,OAAQ,MAkBZ,qCADA,sCADA,mBADA,oBAXA,gBADA,iBAOA,uBADA,wBADA,iBADA,kBADA,wBADA,yBASA,mCADA,oC2DpzME,oBAAA,qBAAA,oBAAA,qB3D2zMF,WADA,YAOA,uBADA,wBADA,qBADA,sBADA,cADA,e2D/zMI,a3Dq0MJ,cDvBC,kB4D7yMG,mB3DqzMJ,WADA,YAwBE,QAAS,MACT,QAAS,IASX,qCADA,mBANA,gBAGA,uBADA,iBADA,wBAIA,mCDhBC,oB6D/0MC,oB5Dk2MF,W+B51MA,uBhCo0MC,qB4D5zMG,cChBF,aACA,kB5D+1MF,W+Br1ME,MAAO,KhCy0MR,cgCt0MC,QAAS,MACT,aAAA,KhCw0MD,YAAA,KgC/zMC,YhCk0MD,MAAA,gBgC/zMC,WhCk0MD,MAAA,egC/zMC,MhCk0MD,QAAA,e8Dz1MC,MACA,QAAA,gBAEA,WACA,WAAA,O9B8BF,WACE,KAAA,EAAA,EAAA,EhCg0MD,MAAA,YgCzzMC,YAAa,KACb,iBAAA,YhC2zMD,OAAA,E+D31MC,Q/D81MD,QAAA,eC4BD,OACE,SAAU,M+Dn4MV,chE42MD,MAAA,aC+BD,YADA,YADA,YADA,YAIE,QAAS,e+Dp5MT,kBhEs4MC,mBgEr4MD,yBhEi4MD,kB+Dl1MD,mBA6IA,yB9D4tMA,kBACA,mB8Dj3ME,yB9D62MF,kBACA,mBACA,yB+Dv5MY,QAAA,eACV,yBAAU,YhE04MT,QAAA,gBC4BD,iB+Dp6MU,QAAA,gBhE64MX,c+D51MG,QAAS,oB/Dg2MV,c+Dl2MC,c/Dm2MH,QAAA,sB+D91MG,yB/Dk2MD,kBACF,QAAA,iB+D91MG,yB/Dk2MD,mBACF,QAAA,kBgEh6MC,yBhEo6MC,yBgEn6MD,QAAA,wBACA,+CAAU,YhEw6MT,QAAA,gBC4BD,iB+Dl8MU,QAAA,gBhE26MX,c+Dr2MG,QAAS,oB/Dy2MV,c+D32MC,c/D42MH,QAAA,sB+Dv2MG,+C/D22MD,kBACF,QAAA,iB+Dv2MG,+C/D22MD,mBACF,QAAA,kBgE97MC,+ChEk8MC,yBgEj8MD,QAAA,wBACA,gDAAU,YhEs8MT,QAAA,gBC4BD,iB+Dh+MU,QAAA,gBhEy8MX,c+D92MG,QAAS,oB/Dk3MV,c+Dp3MC,c/Dq3MH,QAAA,sB+Dh3MG,gD/Do3MD,kBACF,QAAA,iB+Dh3MG,gD/Do3MD,mBACF,QAAA,kBgE59MC,gDhEg+MC,yBgE/9MD,QAAA,wBACA,0BAAU,YhEo+MT,QAAA,gBC4BD,iB+D9/MU,QAAA,gBhEu+MX,c+Dv3MG,QAAS,oB/D23MV,c+D73MC,c/D83MH,QAAA,sB+Dz3MG,0B/D63MD,kBACF,QAAA,iB+Dz3MG,0B/D63MD,mBACF,QAAA,kBgEl/MC,0BhEs/MC,yBACF,QAAA,wBgEv/MC,yBhE2/MC,WACF,QAAA,gBgE5/MC,+ChEggNC,WACF,QAAA,gBgEjgNC,gDhEqgNC,WACF,QAAA,gBAGA,0B+Dh3MC,WA4BE,QAAS,gBC5LX,eAAU,QAAA,eACV,aAAU,ehEyhNT,QAAA,gBC4BD,oB+DnjNU,QAAA,gBhE4hNX,iB+D93MG,QAAS,oBAMX,iB/D23MD,iB+Dt2MG,QAAS,sB/D22MZ,qB+D/3MC,QAAS,e/Dk4MV,a+D53MC,qBAcE,QAAS,iB/Dm3MZ,sB+Dh4MC,QAAS,e/Dm4MV,a+D73MC,sBAOE,QAAS,kB/D23MZ,4B+D53MC,QAAS,eCpLT,ahEojNC,4BACF,QAAA,wBC6BD,aACE,cACE,QAAS","sourcesContent":["/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n border: 0;\n background-color: transparent;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #fff;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #fff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #ccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #fff;\n border: 1px solid #ddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #fff;\n border-color: #ddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #fff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #fff;\n line-height: 1;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n text-decoration: none;\n color: #555;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 12px;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #fff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #fff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #fff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #fff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #fff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -webkit-text-size-adjust: 100%;\n -ms-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n margin: .67em 0;\n font-size: 2em;\n}\nmark {\n color: #000;\n background: #ff0;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n position: relative;\n font-size: 75%;\n line-height: 0;\n vertical-align: baseline;\n}\nsup {\n top: -.5em;\n}\nsub {\n bottom: -.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n height: 0;\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n margin: 0;\n font: inherit;\n color: inherit;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n padding: 0;\n border: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n padding: .35em .625em .75em;\n margin: 0 2px;\n border: 1px solid #c0c0c0;\n}\nlegend {\n padding: 0;\n border: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-spacing: 0;\n border-collapse: collapse;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important;\n text-shadow: none !important;\n background: transparent !important;\n -webkit-box-shadow: none !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n display: inline-block;\n max-width: 100%;\n height: auto;\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all .2s ease-in-out;\n -o-transition: all .2s ease-in-out;\n transition: all .2s ease-in-out;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n padding: .2em;\n background-color: #fcf8e3;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n margin-left: -5px;\n list-style: none;\n}\n.list-inline > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n overflow: hidden;\n clear: left;\n text-align: right;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid #eee;\n border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n color: #333;\n word-break: break-all;\n word-wrap: break-word;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n.row {\n margin-right: -15px;\n margin-left: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n display: table-column;\n float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n display: table-cell;\n float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n min-height: .01%;\n overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n vertical-align: middle;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n min-height: 34px;\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-right: 0;\n padding-left: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n background-color: #f2dede;\n border-color: #a94442;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n padding-top: 7px;\n margin-top: 0;\n margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n padding-top: 7px;\n margin-bottom: 0;\n text-align: right;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n padding: 6px 12px;\n margin-bottom: 0;\n font-size: 14px;\n font-weight: normal;\n line-height: 1.42857143;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n outline: 0;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n opacity: .65;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n font-weight: normal;\n color: #337ab7;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity .15s linear;\n -o-transition: opacity .15s linear;\n transition: opacity .15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-timing-function: ease;\n -o-transition-timing-function: ease;\n transition-timing-function: ease;\n -webkit-transition-duration: .35s;\n -o-transition-duration: .35s;\n transition-duration: .35s;\n -webkit-transition-property: height, visibility;\n -o-transition-property: height, visibility;\n transition-property: height, visibility;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n font-size: 14px;\n text-align: left;\n list-style: none;\n background-color: #fff;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, .15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n color: #262626;\n text-decoration: none;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n background-color: #337ab7;\n outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n content: \"\";\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n right: 0;\n left: auto;\n }\n .navbar-right .dropdown-menu-left {\n right: auto;\n left: 0;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555;\n text-align: center;\n background-color: #eee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eee;\n}\n.nav > li.disabled > a {\n color: #777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777;\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555;\n cursor: default;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n padding-right: 15px;\n padding-left: 15px;\n overflow-x: visible;\n -webkit-overflow-scrolling: touch;\n border-top: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-right: 0;\n padding-left: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n height: 50px;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-top: 8px;\n margin-right: 15px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n padding: 10px 15px;\n margin-top: 8px;\n margin-right: -15px;\n margin-bottom: 8px;\n margin-left: -15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n color: #fff;\n background-color: #080808;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n padding: 0 5px;\n color: #ccc;\n content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n color: #777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n margin-left: -1px;\n line-height: 1.42857143;\n color: #337ab7;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-top-left-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eee;\n border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n cursor: default;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777;\n cursor: not-allowed;\n background-color: #fff;\n border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-top-left-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-top-right-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n text-align: center;\n list-style: none;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777;\n cursor: not-allowed;\n background-color: #fff;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: #777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n padding-right: 15px;\n padding-left: 15px;\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-right: 60px;\n padding-left: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border .2s ease-in-out;\n -o-transition: border .2s ease-in-out;\n transition: border .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-right: auto;\n margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@-o-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n height: 20px;\n margin-bottom: 20px;\n overflow: hidden;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n float: left;\n width: 0;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n -webkit-transition: width .6s ease;\n -o-transition: width .6s ease;\n transition: width .6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n -webkit-background-size: 40px 40px;\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n padding-left: 0;\n margin-bottom: 20px;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n color: #555;\n text-decoration: none;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n color: #777;\n cursor: not-allowed;\n background-color: #eee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-right: 15px;\n padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n margin-bottom: 0;\n border: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n filter: alpha(opacity=20);\n opacity: .2;\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n filter: alpha(opacity=50);\n opacity: .5;\n}\nbutton.close {\n -webkit-appearance: none;\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transition: -webkit-transform .3s ease-out;\n -o-transition: -o-transform .3s ease-out;\n transition: transform .3s ease-out;\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, .2);\n border-radius: 6px;\n outline: 0;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.modal-backdrop.in {\n filter: alpha(opacity=50);\n opacity: .5;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 12px;\n font-style: normal;\n font-weight: normal;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n filter: alpha(opacity=0);\n opacity: 0;\n\n line-break: auto;\n}\n.tooltip.in {\n filter: alpha(opacity=90);\n opacity: .9;\n}\n.tooltip.top {\n padding: 5px 0;\n margin-top: -3px;\n}\n.tooltip.right {\n padding: 0 5px;\n margin-left: 3px;\n}\n.tooltip.bottom {\n padding: 5px 0;\n margin-top: 3px;\n}\n.tooltip.left {\n padding: 0 5px;\n margin-left: -3px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n right: 5px;\n bottom: 0;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n font-style: normal;\n font-weight: normal;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n background-color: #fff;\n -webkit-background-clip: padding-box;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, .2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n\n line-break: auto;\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n padding: 8px 14px;\n margin: 0;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n content: \"\";\n border-width: 10px;\n}\n.popover.top > .arrow {\n bottom: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-color: #999;\n border-top-color: rgba(0, 0, 0, .25);\n border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n bottom: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-color: #fff;\n border-bottom-width: 0;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-right-color: #999;\n border-right-color: rgba(0, 0, 0, .25);\n border-left-width: 0;\n}\n.popover.right > .arrow:after {\n bottom: -10px;\n left: 1px;\n content: \" \";\n border-right-color: #fff;\n border-left-width: 0;\n}\n.popover.bottom > .arrow {\n top: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999;\n border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n top: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999;\n border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n right: 1px;\n bottom: -10px;\n content: \" \";\n border-right-width: 0;\n border-left-color: #fff;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner > .item {\n position: relative;\n display: none;\n -webkit-transition: .6s ease-in-out left;\n -o-transition: .6s ease-in-out left;\n transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform .6s ease-in-out;\n -o-transition: -o-transform .6s ease-in-out;\n transition: transform .6s ease-in-out;\n\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n left: 0;\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n left: 0;\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n left: 0;\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 15%;\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n background-color: rgba(0, 0, 0, 0);\n filter: alpha(opacity=50);\n opacity: .5;\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control.right {\n right: 0;\n left: auto;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n color: #fff;\n text-decoration: none;\n filter: alpha(opacity=90);\n outline: 0;\n opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n border: 1px solid #fff;\n border-radius: 10px;\n}\n.carousel-indicators .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n display: table;\n content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\002a\"; } }\n.glyphicon-plus { &:before { content: \"\\002b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // WebKit-specific. Other browsers will keep their default outline style.\n // (Initially tried to also force default via `outline: initial`,\n // but that seems to erroneously remove the outline in Firefox altogether.)\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @dl-horizontal-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: floor((@gutter / 2));\n padding-right: ceil((@gutter / 2));\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: ceil((@gutter / -2));\n margin-right: floor((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: ceil((@grid-gutter-width / 2));\n padding-right: floor((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Unstyle the caret on ``\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus,\n &.focus {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n .border-top-radius(@btn-border-radius-base);\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n .border-top-radius(0);\n .border-bottom-radius(@btn-border-radius-base);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n\n &:focus {\n z-index: 3;\n }\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @input-border-radius;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @input-border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @input-border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on ",{class:"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("unselect",function(){b.isOpen()&&(d.setClasses(),d.highlightFirstItem())}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):h-g<0&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-b+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");if("true"===c.attr("aria-selected"))return void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{}));d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){return this.$results.find(".select2-results__option--highlighted")},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),c<=2?this.$results.scrollTop(0):(g>this.$results.outerHeight()||g<0)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id,a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2");a(".select2.select2-container--open").each(function(){var b=a(this);this!=d[0]&&b.data("element").select2("close")})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){b.find(".selection").append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html(''),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("focus",function(b){a.isOpen()||c.$selection.focus()}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection");return this.options.get("escapeMarkup")(c(a,b))},e.prototype.selectionContainer=function(){return a("")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html(''),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection");return this.options.get("escapeMarkup")(c(a,b))},d.prototype.selectionContainer=function(){return a('
  • ×
  • ')},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d1||c)return a.call(this,b);this.clear();var d=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(d)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e0||0===c.length)){var d=a('×');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){if(a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented(),a.which===c.BACKSPACE&&""===e.$search.val()){var b=e.$searchContainer.prev(".select2-selection__choice");if(b.length>0){var d=b.data("data");e.searchRemoveChoice(d),a.preventDefault()}}});var f=document.documentMode,g=f&&f<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){if(g)return void e.$selection.off("input.search input.searchcheck");e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{a=.75*(this.$search.val().length+1)+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"}}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),null!=c.id?d+="-"+c.id.toString():d+="-"+a.generateChars(4),d},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h0&&b.term.length>this.maximumInputLength)return void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}});a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;if(d.maximumSelectionLength>0&&f>=d.maximumSelectionLength)return void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}});a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()||e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){e.showSearch(a)?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){e.$results.offset().top+e.$results.outerHeight(!1)+50>=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1)&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('
  • '),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id;this.$container.parents().filter(b.hasScroll).off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),null==l.tokenSeparators&&null==l.tokenizer||(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){null==c(d,e.children[g])&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var h=b(e.text).toUpperCase(),i=b(d.term).toUpperCase();return h.indexOf(i)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)},new D}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return e<=0?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;h=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),null!=a&&0!==a.length||(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("select2/compat/utils",["jquery"],function(a){function b(b,c,d){var e,f,g=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0===this.indexOf("select2-")&&g.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&null!=(f=d(this))&&g.push(f)})),b.attr("class",g.join(" "))}return{syncCssClasses:b}}),b.define("select2/compat/containerCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("containerCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptContainerCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("containerCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/dropdownCss",["jquery","./utils"],function(a,b){function c(a){return null}function d(){}return d.prototype.render=function(d){var e=d.call(this),f=this.options.get("dropdownCssClass")||"";a.isFunction(f)&&(f=f(this.$element));var g=this.options.get("adaptDropdownCssClass");if(g=g||c,-1!==f.indexOf(":all:")){f=f.replace(":all:","");var h=g;g=function(a){var b=h(a);return null!=b?b+" "+a:a}}var i=this.options.get("dropdownCss")||{};return a.isFunction(i)&&(i=i(this.$element)),b.syncCssClasses(e,this.$element,g),e.css(i),e.addClass(f),e},d}),b.define("select2/compat/initSelection",["jquery"],function(a){function b(a,b,c){c.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=c.get("initSelection"),this._isInitialized=!1,a.call(this,b,c)}return b.prototype.current=function(b,c){var d=this;if(this._isInitialized)return void b.call(this,c);this.initSelection.call(null,this.$element,function(b){d._isInitialized=!0,a.isArray(b)||(b=[b]),c(b)})},b}),b.define("select2/compat/inputData",["jquery"],function(a){function b(a,b,c){this._currentData=[],this._valueSeparator=c.get("valueSeparator")||",","hidden"===b.prop("type")&&c.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){if(a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented(),a.which===c.BACKSPACE&&""===e.$search.val()){var b=e.$searchContainer.prev(".select2-selection__choice");if(b.length>0){var d=b.data("data");e.searchRemoveChoice(d),a.preventDefault()}}});var f=document.documentMode,g=f&&f<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){if(g)return void e.$selection.off("input.search input.searchcheck");e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{a=.75*(this.$search.val().length+1)+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"}}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),null!=c.id?d+="-"+c.id.toString():d+="-"+a.generateChars(4),d},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},j,l),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){d.status&&"0"===d.status||e.trigger("results:message",{message:"errorLoading"})});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&null!=a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");void 0!==f&&(this.createTag=f);var g=d.get("insertTag");if(void 0!==g&&(this.insertTag=g),b.call(this,c,d),a.isArray(e))for(var h=0;h0&&b.term.length>this.maximumInputLength)return void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}});a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;if(d.maximumSelectionLength>0&&f>=d.maximumSelectionLength)return void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}});a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("focus",function(){c.isOpen()||e.$search.focus()}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){e.showSearch(a)?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){e.$results.offset().top+e.$results.outerHeight(!1)+50>=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1)&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('
  • '),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a(""),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id;this.$container.parents().filter(b.hasScroll).off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=this.$container.offset();f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.topf.bottom+h.height,l={left:f.left,top:g.bottom},m=this.$dropdownParent;"static"===m.css("position")&&(m=m.offsetParent());var n=m.offset();l.top-=n.top,l.left-=n.left,c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-n.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.position="relative",a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),null==l.tokenSeparators&&null==l.tokenizer||(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){null==c(d,e.children[g])&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var h=b(e.text).toUpperCase(),i=b(d.term).toUpperCase();return h.indexOf(i)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)},new D}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b=b.replace(/(:|\.|\[|\]|,)/g,""),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return e<=0?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;h=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this.$element.on("focus.select2",function(a){b.trigger("focus",a)}),this._syncA=c.bind(this._syncAttributes,this),this._syncS=c.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._syncA),a.each(c,b._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",b._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",b._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",b._syncS,!1))},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype._syncSubtree=function(a,b){var c=!1,d=this;if(!a||!a.target||"OPTION"===a.target.nodeName||"OPTGROUP"===a.target.nodeName){if(b)if(b.addedNodes&&b.addedNodes.length>0)for(var e=0;e0&&(c=!0);else c=!0;c&&this.dataAdapter.current(function(a){d.trigger("selection:update",{data:a})})}},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),null!=a&&0!==a.length||(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if("object"==typeof(b=b||{}))return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d,f=Array.prototype.slice.call(arguments,1);return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2."),d=c[b].apply(c,f)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c}); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/css/select2.css b/InvenTree/InvenTree/static/select2/css/select2.css similarity index 97% rename from InvenTree/InvenTree/static/css/select2.css rename to InvenTree/InvenTree/static/select2/css/select2.css index 447b2b86cc..750b3207ae 100644 --- a/InvenTree/InvenTree/static/css/select2.css +++ b/InvenTree/InvenTree/static/select2/css/select2.css @@ -118,12 +118,14 @@ .select2-hidden-accessible { border: 0 !important; clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(50%) !important; + clip-path: inset(50%) !important; height: 1px !important; - margin: -1px !important; overflow: hidden !important; padding: 0 !important; position: absolute !important; - width: 1px !important; } + width: 1px !important; + white-space: nowrap !important; } .select2-container--default .select2-selection--single { background-color: #fff; @@ -186,16 +188,13 @@ width: 100%; } .select2-container--default .select2-selection--multiple .select2-selection__rendered li { list-style: none; } - .select2-container--default .select2-selection--multiple .select2-selection__placeholder { - color: #999; - margin-top: 5px; - float: left; } .select2-container--default .select2-selection--multiple .select2-selection__clear { cursor: pointer; float: right; font-weight: bold; margin-top: 5px; - margin-right: 10px; } + margin-right: 10px; + padding: 1px; } .select2-container--default .select2-selection--multiple .select2-selection__choice { background-color: #e4e4e4; border: 1px solid #aaa; @@ -214,7 +213,7 @@ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover { color: #333; } -.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline { +.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline { float: right; } .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice { @@ -420,9 +419,7 @@ color: #555; } .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice { - float: right; } - -.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice { + float: right; margin-left: 5px; margin-right: auto; } diff --git a/InvenTree/InvenTree/static/select2/css/select2.min.css b/InvenTree/InvenTree/static/select2/css/select2.min.css new file mode 100644 index 0000000000..7c18ad59df --- /dev/null +++ b/InvenTree/InvenTree/static/select2/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/InvenTree/InvenTree/static/select2/js/i18n/af.js b/InvenTree/InvenTree/static/select2/js/i18n/af.js new file mode 100644 index 0000000000..32e5ac7de8 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/af.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ar.js b/InvenTree/InvenTree/static/select2/js/i18n/ar.js new file mode 100644 index 0000000000..64e1caad34 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ar.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/az.js b/InvenTree/InvenTree/static/select2/js/i18n/az.js new file mode 100644 index 0000000000..1d52c260f2 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/az.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/bg.js b/InvenTree/InvenTree/static/select2/js/i18n/bg.js new file mode 100644 index 0000000000..73b730a705 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/bg.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/bn.js b/InvenTree/InvenTree/static/select2/js/i18n/bn.js new file mode 100644 index 0000000000..2d17b9d8e0 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/bn.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/bs.js b/InvenTree/InvenTree/static/select2/js/i18n/bs.js new file mode 100644 index 0000000000..46b084d758 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/bs.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ca.js b/InvenTree/InvenTree/static/select2/js/i18n/ca.js new file mode 100644 index 0000000000..82dbbb7a21 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ca.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/cs.js b/InvenTree/InvenTree/static/select2/js/i18n/cs.js new file mode 100644 index 0000000000..7116d6c1df --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/cs.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/da.js b/InvenTree/InvenTree/static/select2/js/i18n/da.js new file mode 100644 index 0000000000..cda32c34aa --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/da.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/de.js b/InvenTree/InvenTree/static/select2/js/i18n/de.js new file mode 100644 index 0000000000..c2e61e5800 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/de.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/dsb.js b/InvenTree/InvenTree/static/select2/js/i18n/dsb.js new file mode 100644 index 0000000000..02f283abad --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/dsb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/el.js b/InvenTree/InvenTree/static/select2/js/i18n/el.js new file mode 100644 index 0000000000..d4922a1df5 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/el.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/en.js b/InvenTree/InvenTree/static/select2/js/i18n/en.js new file mode 100644 index 0000000000..3b19285734 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/en.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/es.js b/InvenTree/InvenTree/static/select2/js/i18n/es.js new file mode 100644 index 0000000000..68afd6d259 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/es.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/et.js b/InvenTree/InvenTree/static/select2/js/i18n/et.js new file mode 100644 index 0000000000..070b61a26d --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/et.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/eu.js b/InvenTree/InvenTree/static/select2/js/i18n/eu.js new file mode 100644 index 0000000000..90d5e73f8a --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/eu.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/fa.js b/InvenTree/InvenTree/static/select2/js/i18n/fa.js new file mode 100644 index 0000000000..e1ffdbed0d --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/fa.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها می‌توانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/fi.js b/InvenTree/InvenTree/static/select2/js/i18n/fi.js new file mode 100644 index 0000000000..ffed1247dd --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/fi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/fr.js b/InvenTree/InvenTree/static/select2/js/i18n/fr.js new file mode 100644 index 0000000000..dd02f973ff --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/fr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/gl.js b/InvenTree/InvenTree/static/select2/js/i18n/gl.js new file mode 100644 index 0000000000..208a005705 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/gl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/he.js b/InvenTree/InvenTree/static/select2/js/i18n/he.js new file mode 100644 index 0000000000..25a8805aa0 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/he.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/hi.js b/InvenTree/InvenTree/static/select2/js/i18n/hi.js new file mode 100644 index 0000000000..f3ed798434 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/hi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/hr.js b/InvenTree/InvenTree/static/select2/js/i18n/hr.js new file mode 100644 index 0000000000..cb3268db16 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/hr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/hsb.js b/InvenTree/InvenTree/static/select2/js/i18n/hsb.js new file mode 100644 index 0000000000..3d5bf09dbd --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/hsb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/hu.js b/InvenTree/InvenTree/static/select2/js/i18n/hu.js new file mode 100644 index 0000000000..4893aa2f70 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/hu.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/hy.js b/InvenTree/InvenTree/static/select2/js/i18n/hy.js new file mode 100644 index 0000000000..8230007141 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/hy.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/id.js b/InvenTree/InvenTree/static/select2/js/i18n/id.js new file mode 100644 index 0000000000..4a0b3bf009 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/id.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/is.js b/InvenTree/InvenTree/static/select2/js/i18n/is.js new file mode 100644 index 0000000000..cca5bbecf0 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/is.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/it.js b/InvenTree/InvenTree/static/select2/js/i18n/it.js new file mode 100644 index 0000000000..507c7d9f29 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/it.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ja.js b/InvenTree/InvenTree/static/select2/js/i18n/ja.js new file mode 100644 index 0000000000..451025e2c7 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ja.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ka.js b/InvenTree/InvenTree/static/select2/js/i18n/ka.js new file mode 100644 index 0000000000..60c593b705 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ka.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/km.js b/InvenTree/InvenTree/static/select2/js/i18n/km.js new file mode 100644 index 0000000000..4dca94f414 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/km.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ko.js b/InvenTree/InvenTree/static/select2/js/i18n/ko.js new file mode 100644 index 0000000000..f2880fb004 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ko.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/lt.js b/InvenTree/InvenTree/static/select2/js/i18n/lt.js new file mode 100644 index 0000000000..f6a42155ad --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/lt.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/lv.js b/InvenTree/InvenTree/static/select2/js/i18n/lv.js new file mode 100644 index 0000000000..806dc5c433 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/lv.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/mk.js b/InvenTree/InvenTree/static/select2/js/i18n/mk.js new file mode 100644 index 0000000000..cb7b84a263 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/mk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ms.js b/InvenTree/InvenTree/static/select2/js/i18n/ms.js new file mode 100644 index 0000000000..6bd7eaa3e0 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ms.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/nb.js b/InvenTree/InvenTree/static/select2/js/i18n/nb.js new file mode 100644 index 0000000000..25d89c6870 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/nb.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ne.js b/InvenTree/InvenTree/static/select2/js/i18n/ne.js new file mode 100644 index 0000000000..1c39f67210 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ne.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/nl.js b/InvenTree/InvenTree/static/select2/js/i18n/nl.js new file mode 100644 index 0000000000..2b74058d23 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/nl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/pl.js b/InvenTree/InvenTree/static/select2/js/i18n/pl.js new file mode 100644 index 0000000000..4ca5748c38 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/pl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ps.js b/InvenTree/InvenTree/static/select2/js/i18n/ps.js new file mode 100644 index 0000000000..9b008e4c14 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ps.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/pt-BR.js b/InvenTree/InvenTree/static/select2/js/i18n/pt-BR.js new file mode 100644 index 0000000000..c991e2550a --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/pt-BR.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/pt.js b/InvenTree/InvenTree/static/select2/js/i18n/pt.js new file mode 100644 index 0000000000..b5da1a6b49 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/pt.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ro.js b/InvenTree/InvenTree/static/select2/js/i18n/ro.js new file mode 100644 index 0000000000..1ba7b40bef --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ro.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/ru.js b/InvenTree/InvenTree/static/select2/js/i18n/ru.js new file mode 100644 index 0000000000..63a7d66c3b --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/ru.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sk.js b/InvenTree/InvenTree/static/select2/js/i18n/sk.js new file mode 100644 index 0000000000..5049528ad0 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sl.js b/InvenTree/InvenTree/static/select2/js/i18n/sl.js new file mode 100644 index 0000000000..4d0b7d3e34 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sq.js b/InvenTree/InvenTree/static/select2/js/i18n/sq.js new file mode 100644 index 0000000000..59162024ed --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sq.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sr-Cyrl.js b/InvenTree/InvenTree/static/select2/js/i18n/sr-Cyrl.js new file mode 100644 index 0000000000..ce13ce8f9a --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sr-Cyrl.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sr.js b/InvenTree/InvenTree/static/select2/js/i18n/sr.js new file mode 100644 index 0000000000..dd407a06dc --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/sv.js b/InvenTree/InvenTree/static/select2/js/i18n/sv.js new file mode 100644 index 0000000000..1bc8724a79 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/sv.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/th.js b/InvenTree/InvenTree/static/select2/js/i18n/th.js new file mode 100644 index 0000000000..63eab7114b --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/th.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/tk.js b/InvenTree/InvenTree/static/select2/js/i18n/tk.js new file mode 100644 index 0000000000..30255ff377 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/tk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/tr.js b/InvenTree/InvenTree/static/select2/js/i18n/tr.js new file mode 100644 index 0000000000..fc4c0bf051 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/tr.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/uk.js b/InvenTree/InvenTree/static/select2/js/i18n/uk.js new file mode 100644 index 0000000000..63697e3884 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/uk.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/vi.js b/InvenTree/InvenTree/static/select2/js/i18n/vi.js new file mode 100644 index 0000000000..24f3bc2d61 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/vi.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/zh-CN.js b/InvenTree/InvenTree/static/select2/js/i18n/zh-CN.js new file mode 100644 index 0000000000..2c5649d310 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/zh-CN.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/select2/js/i18n/zh-TW.js b/InvenTree/InvenTree/static/select2/js/i18n/zh-TW.js new file mode 100644 index 0000000000..570a566937 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/i18n/zh-TW.js @@ -0,0 +1,3 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ + +!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}(); \ No newline at end of file diff --git a/InvenTree/InvenTree/static/script/select2/select2.full.js b/InvenTree/InvenTree/static/select2/js/select2.full.js similarity index 89% rename from InvenTree/InvenTree/static/script/select2/select2.full.js rename to InvenTree/InvenTree/static/select2/js/select2.full.js index 608642bf64..358572a657 100644 --- a/InvenTree/InvenTree/static/script/select2/select2.full.js +++ b/InvenTree/InvenTree/static/select2/js/select2.full.js @@ -1,11 +1,11 @@ /*! - * Select2 4.0.5 + * Select2 4.0.13 * https://select2.github.io * * Released under the MIT license * https://github.com/select2/select2/blob/master/LICENSE.md */ -(function (factory) { +;(function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); @@ -574,10 +574,10 @@ S2.define('select2/utils',[ DecoratedClass.prototype = new ctr(); for (var m = 0; m < superMethods.length; m++) { - var superMethod = superMethods[m]; + var superMethod = superMethods[m]; - DecoratedClass.prototype[superMethod] = - SuperClass.prototype[superMethod]; + DecoratedClass.prototype[superMethod] = + SuperClass.prototype[superMethod]; } var calledMethod = function (methodName) { @@ -772,6 +772,70 @@ S2.define('select2/utils',[ $element.append($nodes); }; + // Cache objects in Utils.__cache instead of $.data (see #4346) + Utils.__cache = {}; + + var id = 0; + Utils.GetUniqueElementId = function (element) { + // Get a unique element Id. If element has no id, + // creates a new unique number, stores it in the id + // attribute and returns the new id. + // If an id already exists, it simply returns it. + + var select2Id = element.getAttribute('data-select2-id'); + if (select2Id == null) { + // If element has id, use it. + if (element.id) { + select2Id = element.id; + element.setAttribute('data-select2-id', select2Id); + } else { + element.setAttribute('data-select2-id', ++id); + select2Id = id.toString(); + } + } + return select2Id; + }; + + Utils.StoreData = function (element, name, value) { + // Stores an item in the cache for a specified element. + // name is the cache key. + var id = Utils.GetUniqueElementId(element); + if (!Utils.__cache[id]) { + Utils.__cache[id] = {}; + } + + Utils.__cache[id][name] = value; + }; + + Utils.GetData = function (element, name) { + // Retrieves a value from the cache by its key (name) + // name is optional. If no name specified, return + // all cache items for the specified element. + // and for a specified element. + var id = Utils.GetUniqueElementId(element); + if (name) { + if (Utils.__cache[id]) { + if (Utils.__cache[id][name] != null) { + return Utils.__cache[id][name]; + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } + return $(element).data(name); // Fallback to HTML5 data attribs. + } else { + return Utils.__cache[id]; + } + }; + + Utils.RemoveData = function (element) { + // Removes all cached items for a specified element. + var id = Utils.GetUniqueElementId(element); + if (Utils.__cache[id] != null) { + delete Utils.__cache[id]; + } + + element.removeAttribute('data-select2-id'); + }; + return Utils; }); @@ -791,7 +855,7 @@ S2.define('select2/results',[ Results.prototype.render = function () { var $results = $( - '
      ' + '
        ' ); if (this.options.get('multiple')) { @@ -814,7 +878,7 @@ S2.define('select2/results',[ this.hideLoading(); var $message = $( - '
      • ' ); @@ -907,7 +971,7 @@ S2.define('select2/results',[ $options.each(function () { var $option = $(this); - var item = $.data(this, 'data'); + var item = Utils.GetData(this, 'data'); // id needs to be converted to a string when comparing var id = '' + item.id; @@ -948,11 +1012,16 @@ S2.define('select2/results',[ option.className = 'select2-results__option'; var attrs = { - 'role': 'treeitem', + 'role': 'option', 'aria-selected': 'false' }; - if (data.disabled) { + var matches = window.Element.prototype.matches || + window.Element.prototype.msMatchesSelector || + window.Element.prototype.webkitMatchesSelector; + + if ((data.element != null && matches.call(data.element, ':disabled')) || + (data.element == null && data.disabled)) { delete attrs['aria-selected']; attrs['aria-disabled'] = 'true'; } @@ -1012,7 +1081,7 @@ S2.define('select2/results',[ this.template(data, option); } - $.data(option, 'data', data); + Utils.StoreData(option, 'data', data); return option; }; @@ -1053,7 +1122,10 @@ S2.define('select2/results',[ } self.setClasses(); - self.highlightFirstItem(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } }); container.on('unselect', function () { @@ -1062,7 +1134,10 @@ S2.define('select2/results',[ } self.setClasses(); - self.highlightFirstItem(); + + if (self.options.get('scrollAfterSelect')) { + self.highlightFirstItem(); + } }); container.on('open', function () { @@ -1098,7 +1173,7 @@ S2.define('select2/results',[ return; } - var data = $highlighted.data('data'); + var data = Utils.GetData($highlighted[0], 'data'); if ($highlighted.attr('aria-selected') == 'true') { self.trigger('close', {}); @@ -1116,8 +1191,9 @@ S2.define('select2/results',[ var currentIndex = $options.index($highlighted); - // If we are already at te top, don't move further - if (currentIndex === 0) { + // If we are already at the top, don't move further + // If no options, currentIndex will be -1 + if (currentIndex <= 0) { return; } @@ -1210,7 +1286,7 @@ S2.define('select2/results',[ function (evt) { var $this = $(this); - var data = $this.data('data'); + var data = Utils.GetData(this, 'data'); if ($this.attr('aria-selected') === 'true') { if (self.options.get('multiple')) { @@ -1233,7 +1309,7 @@ S2.define('select2/results',[ this.$results.on('mouseenter', '.select2-results__option[aria-selected]', function (evt) { - var data = $(this).data('data'); + var data = Utils.GetData(this, 'data'); self.getHighlightedResults() .removeClass('select2-results__option--highlighted'); @@ -1348,14 +1424,15 @@ S2.define('select2/selection/base',[ this._tabindex = 0; - if (this.$element.data('old-tabindex') != null) { - this._tabindex = this.$element.data('old-tabindex'); + if (Utils.GetData(this.$element[0], 'old-tabindex') != null) { + this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex'); } else if (this.$element.attr('tabindex') != null) { this._tabindex = this.$element.attr('tabindex'); } $selection.attr('title', this.$element.attr('title')); $selection.attr('tabindex', this._tabindex); + $selection.attr('aria-disabled', 'false'); this.$selection = $selection; @@ -1365,7 +1442,6 @@ S2.define('select2/selection/base',[ BaseSelection.prototype.bind = function (container, $container) { var self = this; - var id = container.id + '-container'; var resultsId = container.id + '-results'; this.container = container; @@ -1408,17 +1484,19 @@ S2.define('select2/selection/base',[ self.$selection.removeAttr('aria-activedescendant'); self.$selection.removeAttr('aria-owns'); - self.$selection.focus(); + self.$selection.trigger('focus'); self._detachCloseHandler(container); }); container.on('enable', function () { self.$selection.attr('tabindex', self._tabindex); + self.$selection.attr('aria-disabled', 'false'); }); container.on('disable', function () { self.$selection.attr('tabindex', '-1'); + self.$selection.attr('aria-disabled', 'true'); }); }; @@ -1441,7 +1519,6 @@ S2.define('select2/selection/base',[ }; BaseSelection.prototype._attachCloseHandler = function (container) { - var self = this; $(document.body).on('mousedown.select2.' + container.id, function (e) { var $target = $(e.target); @@ -1451,13 +1528,11 @@ S2.define('select2/selection/base',[ var $all = $('.select2.select2-container--open'); $all.each(function () { - var $this = $(this); - if (this == $select[0]) { return; } - var $element = $this.data('element'); + var $element = Utils.GetData(this, 'element'); $element.select2('close'); }); @@ -1481,6 +1556,27 @@ S2.define('select2/selection/base',[ throw new Error('The `update` method must be defined in child classes.'); }; + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + BaseSelection.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + BaseSelection.prototype.isDisabled = function () { + return this.options.get('disabled'); + }; + return BaseSelection; }); @@ -1518,7 +1614,10 @@ S2.define('select2/selection/single',[ var id = container.id + '-container'; - this.$selection.find('.select2-selection__rendered').attr('id', id); + this.$selection.find('.select2-selection__rendered') + .attr('id', id) + .attr('role', 'textbox') + .attr('aria-readonly', 'true'); this.$selection.attr('aria-labelledby', id); this.$selection.on('mousedown', function (evt) { @@ -1542,17 +1641,15 @@ S2.define('select2/selection/single',[ container.on('focus', function (evt) { if (!container.isOpen()) { - self.$selection.focus(); + self.$selection.trigger('focus'); } }); - - container.on('selection:update', function (params) { - self.update(params.data); - }); }; SingleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); // clear tooltip on empty }; SingleSelection.prototype.display = function (data, container) { @@ -1578,7 +1675,14 @@ S2.define('select2/selection/single',[ var formatted = this.display(selection, $rendered); $rendered.empty().append(formatted); - $rendered.prop('title', selection.title || selection.text); + + var title = selection.title || selection.text; + + if (title) { + $rendered.attr('title', title); + } else { + $rendered.removeAttr('title'); + } }; return SingleSelection; @@ -1623,14 +1727,14 @@ S2.define('select2/selection/multiple',[ '.select2-selection__choice__remove', function (evt) { // Ignore the event if it is disabled - if (self.options.get('disabled')) { + if (self.isDisabled()) { return; } var $remove = $(this); var $selection = $remove.parent(); - var data = $selection.data('data'); + var data = Utils.GetData($selection[0], 'data'); self.trigger('unselect', { originalEvent: evt, @@ -1641,7 +1745,9 @@ S2.define('select2/selection/multiple',[ }; MultipleSelection.prototype.clear = function () { - this.$selection.find('.select2-selection__rendered').empty(); + var $rendered = this.$selection.find('.select2-selection__rendered'); + $rendered.empty(); + $rendered.removeAttr('title'); }; MultipleSelection.prototype.display = function (data, container) { @@ -1679,9 +1785,14 @@ S2.define('select2/selection/multiple',[ var formatted = this.display(selection, $selection); $selection.append(formatted); - $selection.prop('title', selection.title || selection.text); - $selection.data('data', selection); + var title = selection.title || selection.text; + + if (title) { + $selection.attr('title', title); + } + + Utils.StoreData($selection[0], 'data', selection); $selections.push($selection); } @@ -1746,8 +1857,9 @@ S2.define('select2/selection/placeholder',[ S2.define('select2/selection/allowClear',[ 'jquery', - '../keys' -], function ($, KEYS) { + '../keys', + '../utils' +], function ($, KEYS, Utils) { function AllowClear () { } AllowClear.prototype.bind = function (decorated, container, $container) { @@ -1776,7 +1888,7 @@ S2.define('select2/selection/allowClear',[ AllowClear.prototype._handleClear = function (_, evt) { // Ignore the event if it is disabled - if (this.options.get('disabled')) { + if (this.isDisabled()) { return; } @@ -1789,10 +1901,22 @@ S2.define('select2/selection/allowClear',[ evt.stopPropagation(); - var data = $clear.data('data'); + var data = Utils.GetData($clear[0], 'data'); + + var previousVal = this.$element.val(); + this.$element.val(this.placeholder.id); + + var unselectData = { + data: data + }; + this.trigger('clear', unselectData); + if (unselectData.prevented) { + this.$element.val(previousVal); + return; + } for (var d = 0; d < data.length; d++) { - var unselectData = { + unselectData = { data: data[d] }; @@ -1802,11 +1926,12 @@ S2.define('select2/selection/allowClear',[ // If the event was prevented, don't clear it out. if (unselectData.prevented) { + this.$element.val(previousVal); return; } } - this.$element.val(this.placeholder.id).trigger('change'); + this.$element.trigger('input').trigger('change'); this.trigger('toggle', {}); }; @@ -1829,12 +1954,14 @@ S2.define('select2/selection/allowClear',[ return; } + var removeAll = this.options.get('translations').get('removeAllItems'); + var $remove = $( - '' + + '' + '×' + '' ); - $remove.data('data', data); + Utils.StoreData($remove[0], 'data', data); this.$selection.find('.select2-selection__rendered').prepend($remove); }; @@ -1856,7 +1983,7 @@ S2.define('select2/selection/search',[ '' ); @@ -1873,14 +2000,18 @@ S2.define('select2/selection/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); container.on('open', function () { + self.$search.attr('aria-controls', resultsId); self.$search.trigger('focus'); }); container.on('close', function () { self.$search.val(''); + self.$search.removeAttr('aria-controls'); self.$search.removeAttr('aria-activedescendant'); self.$search.trigger('focus'); }); @@ -1900,7 +2031,11 @@ S2.define('select2/selection/search',[ }); container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.id); + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } }); this.$selection.on('focusin', '.select2-search--inline', function (evt) { @@ -1925,7 +2060,7 @@ S2.define('select2/selection/search',[ .prev('.select2-selection__choice'); if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var item = Utils.GetData($previousChoice[0], 'data'); self.searchRemoveChoice(item); @@ -1934,6 +2069,12 @@ S2.define('select2/selection/search',[ } }); + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + // Try to detect the IE version should the `documentMode` property that // is stored on the document. This is only implemented in IE and is // slightly cleaner than doing a user agent check. @@ -2019,7 +2160,7 @@ S2.define('select2/selection/search',[ this.resizeSearch(); if (searchHadFocus) { - this.$search.focus(); + this.$search.trigger('focus'); } }; @@ -2052,7 +2193,7 @@ S2.define('select2/selection/search',[ var width = ''; if (this.$search.attr('placeholder') !== '') { - width = this.$selection.find('.select2-selection__rendered').innerWidth(); + width = this.$selection.find('.select2-selection__rendered').width(); } else { var minimumWidth = this.$search.val().length + 1; @@ -2076,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[ 'open', 'opening', 'close', 'closing', 'select', 'selecting', - 'unselect', 'unselecting' + 'unselect', 'unselecting', + 'clear', 'clearing' ]; - var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; decorated.call(this, container, $container); @@ -2412,6 +2556,7 @@ S2.define('select2/diacritics',[ '\u019F': 'O', '\uA74A': 'O', '\uA74C': 'O', + '\u0152': 'OE', '\u01A2': 'OI', '\uA74E': 'OO', '\u0222': 'OU', @@ -2821,6 +2966,7 @@ S2.define('select2/diacritics',[ '\uA74B': 'o', '\uA74D': 'o', '\u0275': 'o', + '\u0153': 'oe', '\u01A3': 'oi', '\u0223': 'ou', '\uA74F': 'oo', @@ -2989,8 +3135,9 @@ S2.define('select2/diacritics',[ '\u03CD': '\u03C5', '\u03CB': '\u03C5', '\u03B0': '\u03C5', - '\u03C9': '\u03C9', - '\u03C2': '\u03C3' + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' }; return diacritics; @@ -3075,7 +3222,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = true; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3096,13 +3243,13 @@ S2.define('select2/data/select',[ } self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); } else { var val = data.id; this.$element.val(val); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -3118,7 +3265,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = false; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3136,7 +3283,7 @@ S2.define('select2/data/select',[ self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -3158,7 +3305,7 @@ S2.define('select2/data/select',[ // Remove anything added to child elements this.$element.find('*').each(function () { // Remove any custom data set by Select2 - $.removeData(this, 'data'); + Utils.RemoveData(this); }); }; @@ -3231,7 +3378,7 @@ S2.define('select2/data/select',[ normalizedData.element = option; // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + Utils.StoreData(option, 'data', normalizedData); return $option; }; @@ -3239,7 +3386,7 @@ S2.define('select2/data/select',[ SelectAdapter.prototype.item = function ($option) { var data = {}; - data = $.data($option[0], 'data'); + data = Utils.GetData($option[0], 'data'); if (data != null) { return data; @@ -3277,13 +3424,13 @@ S2.define('select2/data/select',[ data = this._normalizeItem(data); data.element = $option[0]; - $.data($option[0], 'data', data); + Utils.StoreData($option[0], 'data', data); return data; }; SelectAdapter.prototype._normalizeItem = function (item) { - if (!$.isPlainObject(item)) { + if (item !== Object(item)) { item = { id: item, text: item @@ -3329,15 +3476,19 @@ S2.define('select2/data/array',[ 'jquery' ], function (SelectAdapter, Utils, $) { function ArrayAdapter ($element, options) { - var data = options.get('data') || []; + this._dataToConvert = options.get('data') || []; ArrayAdapter.__super__.constructor.call(this, $element, options); - - this.addOptions(this.convertToOptions(data)); } Utils.Extend(ArrayAdapter, SelectAdapter); + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + ArrayAdapter.prototype.select = function (data) { var $option = this.$element.find('option').filter(function (i, elm) { return elm.value == data.id.toString(); @@ -3487,7 +3638,8 @@ S2.define('select2/data/ajax',[ }, function () { // Attempt to detect if a request was aborted // Only works if the transport exposes a status property - if ($request.status && $request.status === '0') { + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { return; } @@ -3626,8 +3778,6 @@ S2.define('select2/data/tags',[ }; Tags.prototype._removeOldTags = function (_) { - var tag = this._lastTag; - var $options = this.$element.find('option[data-select2-tag]'); $options.each(function () { @@ -3702,7 +3852,7 @@ S2.define('select2/data/tokenizer',[ // Replace the search term if we have the search box if (this.$search.length) { this.$search.val(tokenData.term); - this.$search.focus(); + this.$search.trigger('focus'); } params.term = tokenData.term; @@ -3831,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[ decorated.call(this, $e, options); } + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + MaximumSelectionLength.prototype.query = function (decorated, params, callback) { var self = this; + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + this.current(function (currentData) { var count = currentData != null ? currentData.length : 0; if (self.maximumSelectionLength > 0 && @@ -3847,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[ }); return; } - decorated.call(self, params, callback); + + if (successCallback) { + successCallback(); + } }); }; @@ -3886,7 +4059,7 @@ S2.define('select2/dropdown',[ }; Dropdown.prototype.position = function ($dropdown, $container) { - // Should be implmented in subclasses + // Should be implemented in subclasses }; Dropdown.prototype.destroy = function () { @@ -3910,7 +4083,7 @@ S2.define('select2/dropdown/search',[ '' + '' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '' ); @@ -3925,6 +4098,8 @@ S2.define('select2/dropdown/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); this.$search.on('keydown', function (evt) { @@ -3947,23 +4122,27 @@ S2.define('select2/dropdown/search',[ container.on('open', function () { self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); - self.$search.focus(); + self.$search.trigger('focus'); window.setTimeout(function () { - self.$search.focus(); + self.$search.trigger('focus'); }, 0); }); container.on('close', function () { self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); self.$search.val(''); + self.$search.trigger('blur'); }); container.on('focus', function () { if (!container.isOpen()) { - self.$search.focus(); + self.$search.trigger('focus'); } }); @@ -3978,6 +4157,14 @@ S2.define('select2/dropdown/search',[ } } }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); }; Search.prototype.handleSearch = function (evt) { @@ -4062,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[ if (this.showLoadingMore(data)) { this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); } }; @@ -4080,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[ self.loading = true; }); - this.$results.on('scroll', function () { - var isLoadMoreVisible = $.contains( - document.documentElement, - self.$loadingMore[0] - ); + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; - if (self.loading || !isLoadMoreVisible) { - return; - } + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var loadingMoreOffset = self.$loadingMore.offset().top + - self.$loadingMore.outerHeight(false); + if (this.loading || !isLoadMoreVisible) { + return; + } - if (currentOffset + 50 >= loadingMoreOffset) { - self.loadMore(); - } - }); + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } }; InfiniteScroll.prototype.loadMore = function () { @@ -4119,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[ var $option = $( '
      • ' + 'role="option" aria-disabled="true">' ); var message = this.options.get('translations').get('loadingMore'); @@ -4137,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[ '../utils' ], function ($, Utils) { function AttachBody (decorated, $element, options) { - this.$dropdownParent = options.get('dropdownParent') || $(document.body); + this.$dropdownParent = $(options.get('dropdownParent') || document.body); decorated.call(this, $element, options); } @@ -4145,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[ AttachBody.prototype.bind = function (decorated, container, $container) { var self = this; - var setupResultsEvents = false; - decorated.call(this, container, $container); container.on('open', function () { self._showDropdown(); self._attachPositioningHandler(container); - if (!setupResultsEvents) { - setupResultsEvents = true; - - container.on('results:all', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - - container.on('results:append', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - } + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); }); container.on('close', function () { @@ -4214,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[ this.$dropdownContainer.detach(); }; + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + AttachBody.prototype._attachPositioningHandler = function (decorated, container) { var self = this; @@ -4224,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[ var $watchers = this.$container.parents().filter(Utils.hasScroll); $watchers.each(function () { - $(this).data('select2-scroll-position', { + Utils.StoreData(this, 'select2-scroll-position', { x: $(this).scrollLeft(), y: $(this).scrollTop() }); }); $watchers.on(scrollEvent, function (ev) { - var position = $(this).data('select2-scroll-position'); + var position = Utils.GetData(this, 'select2-scroll-position'); $(this).scrollTop(position.y); }); @@ -4290,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[ top: container.bottom }; - // Determine what the parent element is to use for calciulating the offset + // Determine what the parent element is to use for calculating the offset var $offsetParent = this.$dropdownParent; - // For statically positoned elements, we need to get the element + // For statically positioned elements, we need to get the element // that is determining the offset if ($offsetParent.css('position') === 'static') { $offsetParent = $offsetParent.offsetParent(); } - var parentOffset = $offsetParent.offset(); + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } css.top -= parentOffset.top; css.left -= parentOffset.left; @@ -4396,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[ }); S2.define('select2/dropdown/selectOnClose',[ - -], function () { + '../utils' +], function (Utils) { function SelectOnClose () { } SelectOnClose.prototype.bind = function (decorated, container, $container) { @@ -4428,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[ return; } - var data = $highlightedResults.data('data'); + var data = Utils.GetData($highlightedResults[0], 'data'); // Don't re-select already selected resulte if ( @@ -4469,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[ var originalEvent = evt.originalEvent; // Don't close if the control key is being held - if (originalEvent && originalEvent.ctrlKey) { + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { return; } @@ -4523,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () { }, searching: function () { return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; } }; }); @@ -4761,66 +4989,29 @@ S2.define('select2/defaults',[ ); } - if (typeof options.language === 'string') { - // Check if the language is specified with a region - if (options.language.indexOf('-') > 0) { - // Extract the region information if it is included - var languageParts = options.language.split('-'); - var baseLanguage = languageParts[0]; + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); - options.language = [options.language, baseLanguage]; - } else { - options.language = [options.language]; + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); } } - if ($.isArray(options.language)) { - var languages = new Translation(); - options.language.push('en'); + options.language = uniqueLanguages; - var languageNames = options.language; - - for (var l = 0; l < languageNames.length; l++) { - var name = languageNames[l]; - var language = {}; - - try { - // Try to load it with the original name - language = Translation.loadPath(name); - } catch (e) { - try { - // If we couldn't load it, check if it wasn't the full path - name = this.defaults.amdLanguageBase + name; - language = Translation.loadPath(name); - } catch (ex) { - // The translation could not be loaded at all. Sometimes this is - // because of a configuration problem, other times this can be - // because of how Select2 helps load all possible translation files. - if (options.debug && window.console && console.warn) { - console.warn( - 'Select2: The language file for "' + name + '" could not be ' + - 'automatically loaded. A fallback will be used instead.' - ); - } - - continue; - } - } - - languages.extend(language); - } - - options.translations = languages; - } else { - var baseTranslation = Translation.loadPath( - this.defaults.amdLanguageBase + 'en' - ); - var customTranslation = new Translation(options.language); - - customTranslation.extend(baseTranslation); - - options.translations = customTranslation; - } + options.translations = this._processTranslations( + options.language, + options.debug + ); return options; }; @@ -4887,13 +5078,14 @@ S2.define('select2/defaults',[ debug: false, dropdownAutoWidth: false, escapeMarkup: Utils.escapeMarkup, - language: EnglishTranslation, + language: {}, matcher: matcher, minimumInputLength: 0, maximumInputLength: 0, maximumSelectionLength: 0, minimumResultsForSearch: 0, selectOnClose: false, + scrollAfterSelect: false, sorter: function (data) { return data; }, @@ -4908,6 +5100,103 @@ S2.define('select2/defaults',[ }; }; + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + Defaults.prototype.set = function (key, value) { var camelKey = $.camelCase(key); @@ -4916,7 +5205,7 @@ S2.define('select2/defaults',[ var convertedData = Utils._convertData(data); - $.extend(this.defaults, convertedData); + $.extend(true, this.defaults, convertedData); }; var defaults = new Defaults(); @@ -4937,6 +5226,10 @@ S2.define('select2/options',[ this.fromElement($element); } + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + this.options = Defaults.apply(this.options); if ($element && $element.is('input')) { @@ -4960,14 +5253,6 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } - if (this.options.language == null) { - if ($e.prop('lang')) { - this.options.language = $e.prop('lang').toLowerCase(); - } else if ($e.closest('[lang]').prop('lang')) { - this.options.language = $e.closest('[lang]').prop('lang'); - } - } - if (this.options.dir == null) { if ($e.prop('dir')) { this.options.dir = $e.prop('dir'); @@ -4981,7 +5266,7 @@ S2.define('select2/options',[ $e.prop('disabled', this.options.disabled); $e.prop('multiple', this.options.multiple); - if ($e.data('select2Tags')) { + if (Utils.GetData($e[0], 'select2Tags')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-select2-tags` attribute has been changed to ' + @@ -4990,11 +5275,11 @@ S2.define('select2/options',[ ); } - $e.data('data', $e.data('select2Tags')); - $e.data('tags', true); + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); } - if ($e.data('ajaxUrl')) { + if (Utils.GetData($e[0], 'ajaxUrl')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-ajax-url` attribute has been changed to ' + @@ -5003,21 +5288,45 @@ S2.define('select2/options',[ ); } - $e.attr('ajax--url', $e.data('ajaxUrl')); - $e.data('ajax--url', $e.data('ajaxUrl')); + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); } var dataset = {}; + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + // Prefer the element's `dataset` attribute if it exists // jQuery 1.x does not correctly handle data attributes with multiple dashes if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { - dataset = $.extend(true, {}, $e[0].dataset, $e.data()); - } else { - dataset = $e.data(); + dataset = $.extend(true, {}, $e[0].dataset, dataset); } - var data = $.extend(true, {}, dataset); + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); data = Utils._convertData(data); @@ -5054,8 +5363,8 @@ S2.define('select2/core',[ './keys' ], function ($, Options, Utils, KEYS) { var Select2 = function ($element, options) { - if ($element.data('select2') != null) { - $element.data('select2').destroy(); + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); } this.$element = $element; @@ -5071,7 +5380,7 @@ S2.define('select2/core',[ // Set up the tabindex var tabindex = $element.attr('tabindex') || 0; - $element.data('old-tabindex', tabindex); + Utils.StoreData($element[0], 'old-tabindex', tabindex); $element.attr('tabindex', '-1'); // Set up containers and adapters @@ -5132,6 +5441,9 @@ S2.define('select2/core',[ // Synchronize any monitored attributes this._syncAttributes(); + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). $element.data('select2', this); }; @@ -5208,6 +5520,12 @@ S2.define('select2/core',[ return null; } + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + return method; }; @@ -5248,8 +5566,8 @@ S2.define('select2/core',[ if (observer != null) { this._observer = new observer(function (mutations) { - $.each(mutations, self._syncA); - $.each(mutations, self._syncS); + self._syncA(); + self._syncS(null, mutations); }); this._observer.observe(this.$element[0], { attributes: true, @@ -5371,7 +5689,7 @@ S2.define('select2/core',[ if (self.isOpen()) { if (key === KEYS.ESC || key === KEYS.TAB || (key === KEYS.UP && evt.altKey)) { - self.close(); + self.close(evt); evt.preventDefault(); } else if (key === KEYS.ENTER) { @@ -5405,7 +5723,7 @@ S2.define('select2/core',[ Select2.prototype._syncAttributes = function () { this.options.set('disabled', this.$element.prop('disabled')); - if (this.options.get('disabled')) { + if (this.isDisabled()) { if (this.isOpen()) { this.close(); } @@ -5416,7 +5734,7 @@ S2.define('select2/core',[ } }; - Select2.prototype._syncSubtree = function (evt, mutations) { + Select2.prototype._isChangeMutation = function (evt, mutations) { var changed = false; var self = this; @@ -5444,7 +5762,22 @@ S2.define('select2/core',[ } } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; // Only re-pull the data if we think there is a change if (changed) { @@ -5466,7 +5799,8 @@ S2.define('select2/core',[ 'open': 'opening', 'close': 'closing', 'select': 'selecting', - 'unselect': 'unselecting' + 'unselect': 'unselecting', + 'clear': 'clearing' }; if (args === undefined) { @@ -5494,7 +5828,7 @@ S2.define('select2/core',[ }; Select2.prototype.toggleDropdown = function () { - if (this.options.get('disabled')) { + if (this.isDisabled()) { return; } @@ -5510,15 +5844,40 @@ S2.define('select2/core',[ return; } + if (this.isDisabled()) { + return; + } + this.trigger('query', {}); }; - Select2.prototype.close = function () { + Select2.prototype.close = function (evt) { if (!this.isOpen()) { return; } - this.trigger('close', {}); + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); }; Select2.prototype.isOpen = function () { @@ -5595,7 +5954,7 @@ S2.define('select2/core',[ }); } - this.$element.val(newVal).trigger('change'); + this.$element.val(newVal).trigger('input').trigger('change'); }; Select2.prototype.destroy = function () { @@ -5621,10 +5980,12 @@ S2.define('select2/core',[ this._syncS = null; this.$element.off('.select2'); - this.$element.attr('tabindex', this.$element.data('old-tabindex')); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); this.$element.removeClass('select2-hidden-accessible'); this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); this.$element.removeData('select2'); this.dataAdapter.destroy(); @@ -5652,7 +6013,7 @@ S2.define('select2/core',[ this.$container.addClass('select2-container--' + this.options.get('theme')); - $container.data('element', this.$element); + Utils.StoreData($container[0], 'element', this.$element); return $container; }; @@ -5862,8 +6223,9 @@ S2.define('select2/compat/initSelection',[ }); S2.define('select2/compat/inputData',[ - 'jquery' -], function ($) { + 'jquery', + '../utils' +], function ($, Utils) { function InputData (decorated, $element, options) { this._currentData = []; this._valueSeparator = options.get('valueSeparator') || ','; @@ -5927,13 +6289,13 @@ S2.define('select2/compat/inputData',[ }); this.$element.val(data.id); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } else { var value = this.$element.val(); value += this._valueSeparator + data.id; this.$element.val(value); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -5956,7 +6318,7 @@ S2.define('select2/compat/inputData',[ } self.$element.val(values.join(self._valueSeparator)); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -5980,7 +6342,7 @@ S2.define('select2/compat/inputData',[ InputData.prototype.addOptions = function (_, $options) { var options = $.map($options, function ($option) { - return $.data($option[0], 'data'); + return Utils.GetData($option[0], 'data'); }); this._currentData.push.apply(this._currentData, options); @@ -6383,8 +6745,9 @@ S2.define('jquery.select2',[ 'jquery-mousewheel', './select2/core', - './select2/defaults' -], function ($, _, Select2, Defaults) { + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { if ($.fn.select2 == null) { // All methods that should return the element var thisMethods = ['open', 'close', 'destroy']; @@ -6405,7 +6768,7 @@ S2.define('jquery.select2',[ var args = Array.prototype.slice.call(arguments, 1); this.each(function () { - var instance = $(this).data('select2'); + var instance = Utils.GetData(this, 'select2'); if (instance == null && window.console && console.error) { console.error( diff --git a/InvenTree/InvenTree/static/select2/js/select2.full.min.js b/InvenTree/InvenTree/static/select2/js/select2.full.min.js new file mode 100644 index 0000000000..fa781916e8 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/select2.full.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(d){var e=function(){if(d&&d.fn&&d.fn.select2&&d.fn.select2.amd)var e=d.fn.select2.amd;var t,n,i,h,o,s,f,g,m,v,y,_,r,a,w,l;function b(e,t){return r.call(e,t)}function c(e,t){var n,i,r,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&w.test(e[s])&&(e[s]=e[s].replace(w,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},r.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},r.__cache={};var n=0;return r.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},r.StoreData=function(e,t,n){var i=r.GetUniqueElementId(e);r.__cache[i]||(r.__cache[i]={}),r.__cache[i][t]=n},r.GetData=function(e,t){var n=r.GetUniqueElementId(e);return t?r.__cache[n]&&null!=r.__cache[n][t]?r.__cache[n][t]:o(e).data(t):r.__cache[n]},r.RemoveData=function(e){var t=r.GetUniqueElementId(e);null!=r.__cache[t]&&delete r.__cache[t],e.removeAttribute("data-select2-id")},r}),e.define("select2/results",["jquery","./utils"],function(h,f){function i(e,t,n){this.$element=e,this.data=n,this.options=t,i.__super__.constructor.call(this)}return f.Extend(i,f.Observable),i.prototype.render=function(){var e=h('
          ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},i.prototype.clear=function(){this.$results.empty()},i.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),i=this.options.get("translations").get(e.message);n.append(t(i(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},i.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},i.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},i.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var i=n-1;0===e.length&&(i=0);var r=t.eq(i);r.trigger("mouseenter");var o=l.$results.offset().top,s=r.offset().top,a=l.$results.scrollTop()+(s-o);0===i?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var i=t.eq(n);i.trigger("mouseenter");var r=l.$results.offset().top+l.$results.outerHeight(!1),o=i.offset().top+i.outerHeight(!1),s=l.$results.scrollTop()+o-r;0===n?l.$results.scrollTop(0):rthis.$results.outerHeight()||o<0)&&this.$results.scrollTop(r)}},i.prototype.template=function(e,t){var n=this.options.get("templateResult"),i=this.options.get("escapeMarkup"),r=n(e,t);null==r?t.style.display="none":"string"==typeof r?t.innerHTML=i(r):h(t).append(r)},i}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,i,r){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return i.Extend(o,i.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=i.GetData(this.$element[0],"old-tabindex")?this._tabindex=i.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,i=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===r.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",i),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&i.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,i){function r(){r.__super__.constructor.apply(this,arguments)}return n.Extend(r,t),r.prototype.render=function(){var e=r.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},r.prototype.bind=function(t,e){var n=this;r.__super__.bind.apply(this,arguments);var i=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",i).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",i),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return e("")},r.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),i=this.display(t,n);n.empty().append(i);var r=t.title||t.text;r?n.attr("title",r):n.removeAttr("title")}else this.clear()},r}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(r,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
            '),e},n.prototype.bind=function(e,t){var i=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){i.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!i.isDisabled()){var t=r(this).parent(),n=l.GetData(t[0],"data");i.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return r('
          • ×
          • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×
            ');a.StoreData(i[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(i)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(i,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=i('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),t.on("open",function(){i.$search.attr("aria-controls",r),i.$search.trigger("focus")}),t.on("close",function(){i.$search.val(""),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.trigger("focus")}),t.on("enable",function(){i.$search.prop("disabled",!1),i._transferTabIndex()}),t.on("disable",function(){i.$search.prop("disabled",!0)}),t.on("focus",function(e){i.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){i.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){i._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===i.$search.val()){var t=i.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("select",function(){i._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var i=this;this._checkIfMaximumSelected(function(){e.call(i,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var i=this;this.current(function(e){var t=null!=e?e.length:0;0=i.maximumSelectionLength?i.trigger("results:message",{message:"maximumSelected",args:{maximum:i.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var i=this,r=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){i.trigger("keypress",e),i._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){i.handleSearch(e)}),t.on("open",function(){i.$search.attr("tabindex",0),i.$search.attr("aria-controls",r),i.$search.trigger("focus"),window.setTimeout(function(){i.$search.trigger("focus")},0)}),t.on("close",function(){i.$search.attr("tabindex",-1),i.$search.removeAttr("aria-controls"),i.$search.removeAttr("aria-activedescendant"),i.$search.val(""),i.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||i.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(i.showSearch(e)?i.$searchContainer.removeClass("select2-search--hide"):i.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?i.$search.attr("aria-activedescendant",e.data._resultId):i.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,i){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,i)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),i=t.length-1;0<=i;i--){var r=t[i];this.placeholder.id===r.id&&n.splice(i,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,i){this.lastParams={},e.call(this,t,n,i),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("query",function(e){i.lastParams=e,i.loading=!0}),t.on("query:append",function(e){i.lastParams=e,i.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
          • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var i=this;e.call(this,t,n),t.on("open",function(){i._showDropdown(),i._attachPositioningHandler(t),i._bindContainerResultHandlers(t)}),t.on("close",function(){i._hideDropdown(),i._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,i="scroll.select2."+t.id,r="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(i,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(i+" "+r+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+i+" "+r)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),i=null,r=this.$container.offset();r.bottom=r.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=r.top,o.bottom=r.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ar.bottom+s,d={left:r.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(i="below"),u||!c||t?!c&&u&&t&&(i="below"):i="above",("above"==i||t&&"below"!==i)&&(d.top=o.top-h.top-s),null!=i&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+i),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+i)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,i){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,i)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,i=0;i');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("select2/compat/utils",["jquery"],function(s){return{syncCssClasses:function(e,t,n){var i,r,o=[];(i=s.trim(e.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0===this.indexOf("select2-")&&o.push(this)}),(i=s.trim(t.attr("class")))&&s((i=""+i).split(/\s+/)).each(function(){0!==this.indexOf("select2-")&&null!=(r=n(this))&&o.push(r)}),e.attr("class",o.join(" "))}}}),e.define("select2/compat/containerCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("containerCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptContainerCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("containerCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/dropdownCss",["jquery","./utils"],function(s,a){function l(e){return null}function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("dropdownCssClass")||"";s.isFunction(n)&&(n=n(this.$element));var i=this.options.get("adaptDropdownCssClass");if(i=i||l,-1!==n.indexOf(":all:")){n=n.replace(":all:","");var r=i;i=function(e){var t=r(e);return null!=t?t+" "+e:e}}var o=this.options.get("dropdownCss")||{};return s.isFunction(o)&&(o=o(this.$element)),a.syncCssClasses(t,this.$element,i),t.css(o),t.addClass(n),t},e}),e.define("select2/compat/initSelection",["jquery"],function(i){function e(e,t,n){n.get("debug")&&window.console&&console.warn&&console.warn("Select2: The `initSelection` option has been deprecated in favor of a custom data adapter that overrides the `current` method. This method is now called multiple times instead of a single time when the instance is initialized. Support will be removed for the `initSelection` option in future versions of Select2"),this.initSelection=n.get("initSelection"),this._isInitialized=!1,e.call(this,t,n)}return e.prototype.current=function(e,t){var n=this;this._isInitialized?e.call(this,t):this.initSelection.call(null,this.$element,function(e){n._isInitialized=!0,i.isArray(e)||(e=[e]),t(e)})},e}),e.define("select2/compat/inputData",["jquery","../utils"],function(s,i){function e(e,t,n){this._currentData=[],this._valueSeparator=n.get("valueSeparator")||",","hidden"===t.prop("type")&&n.get("debug")&&console&&console.warn&&console.warn("Select2: Using a hidden input with Select2 is no longer supported and may stop working in the future. It is recommended to use a `' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '' ); @@ -1873,14 +2000,18 @@ S2.define('select2/selection/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); container.on('open', function () { + self.$search.attr('aria-controls', resultsId); self.$search.trigger('focus'); }); container.on('close', function () { self.$search.val(''); + self.$search.removeAttr('aria-controls'); self.$search.removeAttr('aria-activedescendant'); self.$search.trigger('focus'); }); @@ -1900,7 +2031,11 @@ S2.define('select2/selection/search',[ }); container.on('results:focus', function (params) { - self.$search.attr('aria-activedescendant', params.id); + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } }); this.$selection.on('focusin', '.select2-search--inline', function (evt) { @@ -1925,7 +2060,7 @@ S2.define('select2/selection/search',[ .prev('.select2-selection__choice'); if ($previousChoice.length > 0) { - var item = $previousChoice.data('data'); + var item = Utils.GetData($previousChoice[0], 'data'); self.searchRemoveChoice(item); @@ -1934,6 +2069,12 @@ S2.define('select2/selection/search',[ } }); + this.$selection.on('click', '.select2-search--inline', function (evt) { + if (self.$search.val()) { + evt.stopPropagation(); + } + }); + // Try to detect the IE version should the `documentMode` property that // is stored on the document. This is only implemented in IE and is // slightly cleaner than doing a user agent check. @@ -2019,7 +2160,7 @@ S2.define('select2/selection/search',[ this.resizeSearch(); if (searchHadFocus) { - this.$search.focus(); + this.$search.trigger('focus'); } }; @@ -2052,7 +2193,7 @@ S2.define('select2/selection/search',[ var width = ''; if (this.$search.attr('placeholder') !== '') { - width = this.$selection.find('.select2-selection__rendered').innerWidth(); + width = this.$selection.find('.select2-selection__rendered').width(); } else { var minimumWidth = this.$search.val().length + 1; @@ -2076,10 +2217,13 @@ S2.define('select2/selection/eventRelay',[ 'open', 'opening', 'close', 'closing', 'select', 'selecting', - 'unselect', 'unselecting' + 'unselect', 'unselecting', + 'clear', 'clearing' ]; - var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting']; + var preventableEvents = [ + 'opening', 'closing', 'selecting', 'unselecting', 'clearing' + ]; decorated.call(this, container, $container); @@ -2412,6 +2556,7 @@ S2.define('select2/diacritics',[ '\u019F': 'O', '\uA74A': 'O', '\uA74C': 'O', + '\u0152': 'OE', '\u01A2': 'OI', '\uA74E': 'OO', '\u0222': 'OU', @@ -2821,6 +2966,7 @@ S2.define('select2/diacritics',[ '\uA74B': 'o', '\uA74D': 'o', '\u0275': 'o', + '\u0153': 'oe', '\u01A3': 'oi', '\u0223': 'ou', '\uA74F': 'oo', @@ -2989,8 +3135,9 @@ S2.define('select2/diacritics',[ '\u03CD': '\u03C5', '\u03CB': '\u03C5', '\u03B0': '\u03C5', - '\u03C9': '\u03C9', - '\u03C2': '\u03C3' + '\u03CE': '\u03C9', + '\u03C2': '\u03C3', + '\u2019': '\'' }; return diacritics; @@ -3075,7 +3222,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = true; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3096,13 +3243,13 @@ S2.define('select2/data/select',[ } self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); } else { var val = data.id; this.$element.val(val); - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); } }; @@ -3118,7 +3265,7 @@ S2.define('select2/data/select',[ if ($(data.element).is('option')) { data.element.selected = false; - this.$element.trigger('change'); + this.$element.trigger('input').trigger('change'); return; } @@ -3136,7 +3283,7 @@ S2.define('select2/data/select',[ self.$element.val(val); - self.$element.trigger('change'); + self.$element.trigger('input').trigger('change'); }); }; @@ -3158,7 +3305,7 @@ S2.define('select2/data/select',[ // Remove anything added to child elements this.$element.find('*').each(function () { // Remove any custom data set by Select2 - $.removeData(this, 'data'); + Utils.RemoveData(this); }); }; @@ -3231,7 +3378,7 @@ S2.define('select2/data/select',[ normalizedData.element = option; // Override the option's data with the combined data - $.data(option, 'data', normalizedData); + Utils.StoreData(option, 'data', normalizedData); return $option; }; @@ -3239,7 +3386,7 @@ S2.define('select2/data/select',[ SelectAdapter.prototype.item = function ($option) { var data = {}; - data = $.data($option[0], 'data'); + data = Utils.GetData($option[0], 'data'); if (data != null) { return data; @@ -3277,13 +3424,13 @@ S2.define('select2/data/select',[ data = this._normalizeItem(data); data.element = $option[0]; - $.data($option[0], 'data', data); + Utils.StoreData($option[0], 'data', data); return data; }; SelectAdapter.prototype._normalizeItem = function (item) { - if (!$.isPlainObject(item)) { + if (item !== Object(item)) { item = { id: item, text: item @@ -3329,15 +3476,19 @@ S2.define('select2/data/array',[ 'jquery' ], function (SelectAdapter, Utils, $) { function ArrayAdapter ($element, options) { - var data = options.get('data') || []; + this._dataToConvert = options.get('data') || []; ArrayAdapter.__super__.constructor.call(this, $element, options); - - this.addOptions(this.convertToOptions(data)); } Utils.Extend(ArrayAdapter, SelectAdapter); + ArrayAdapter.prototype.bind = function (container, $container) { + ArrayAdapter.__super__.bind.call(this, container, $container); + + this.addOptions(this.convertToOptions(this._dataToConvert)); + }; + ArrayAdapter.prototype.select = function (data) { var $option = this.$element.find('option').filter(function (i, elm) { return elm.value == data.id.toString(); @@ -3487,7 +3638,8 @@ S2.define('select2/data/ajax',[ }, function () { // Attempt to detect if a request was aborted // Only works if the transport exposes a status property - if ($request.status && $request.status === '0') { + if ('status' in $request && + ($request.status === 0 || $request.status === '0')) { return; } @@ -3626,8 +3778,6 @@ S2.define('select2/data/tags',[ }; Tags.prototype._removeOldTags = function (_) { - var tag = this._lastTag; - var $options = this.$element.find('option[data-select2-tag]'); $options.each(function () { @@ -3702,7 +3852,7 @@ S2.define('select2/data/tokenizer',[ // Replace the search term if we have the search box if (this.$search.length) { this.$search.val(tokenData.term); - this.$search.focus(); + this.$search.trigger('focus'); } params.term = tokenData.term; @@ -3831,10 +3981,30 @@ S2.define('select2/data/maximumSelectionLength',[ decorated.call(this, $e, options); } + MaximumSelectionLength.prototype.bind = + function (decorated, container, $container) { + var self = this; + + decorated.call(this, container, $container); + + container.on('select', function () { + self._checkIfMaximumSelected(); + }); + }; + MaximumSelectionLength.prototype.query = function (decorated, params, callback) { var self = this; + this._checkIfMaximumSelected(function () { + decorated.call(self, params, callback); + }); + }; + + MaximumSelectionLength.prototype._checkIfMaximumSelected = + function (_, successCallback) { + var self = this; + this.current(function (currentData) { var count = currentData != null ? currentData.length : 0; if (self.maximumSelectionLength > 0 && @@ -3847,7 +4017,10 @@ S2.define('select2/data/maximumSelectionLength',[ }); return; } - decorated.call(self, params, callback); + + if (successCallback) { + successCallback(); + } }); }; @@ -3886,7 +4059,7 @@ S2.define('select2/dropdown',[ }; Dropdown.prototype.position = function ($dropdown, $container) { - // Should be implmented in subclasses + // Should be implemented in subclasses }; Dropdown.prototype.destroy = function () { @@ -3910,7 +4083,7 @@ S2.define('select2/dropdown/search',[ '' + '' + + ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' + '' ); @@ -3925,6 +4098,8 @@ S2.define('select2/dropdown/search',[ Search.prototype.bind = function (decorated, container, $container) { var self = this; + var resultsId = container.id + '-results'; + decorated.call(this, container, $container); this.$search.on('keydown', function (evt) { @@ -3947,23 +4122,27 @@ S2.define('select2/dropdown/search',[ container.on('open', function () { self.$search.attr('tabindex', 0); + self.$search.attr('aria-controls', resultsId); - self.$search.focus(); + self.$search.trigger('focus'); window.setTimeout(function () { - self.$search.focus(); + self.$search.trigger('focus'); }, 0); }); container.on('close', function () { self.$search.attr('tabindex', -1); + self.$search.removeAttr('aria-controls'); + self.$search.removeAttr('aria-activedescendant'); self.$search.val(''); + self.$search.trigger('blur'); }); container.on('focus', function () { if (!container.isOpen()) { - self.$search.focus(); + self.$search.trigger('focus'); } }); @@ -3978,6 +4157,14 @@ S2.define('select2/dropdown/search',[ } } }); + + container.on('results:focus', function (params) { + if (params.data._resultId) { + self.$search.attr('aria-activedescendant', params.data._resultId); + } else { + self.$search.removeAttr('aria-activedescendant'); + } + }); }; Search.prototype.handleSearch = function (evt) { @@ -4062,6 +4249,7 @@ S2.define('select2/dropdown/infiniteScroll',[ if (this.showLoadingMore(data)) { this.$results.append(this.$loadingMore); + this.loadMoreIfNeeded(); } }; @@ -4080,25 +4268,27 @@ S2.define('select2/dropdown/infiniteScroll',[ self.loading = true; }); - this.$results.on('scroll', function () { - var isLoadMoreVisible = $.contains( - document.documentElement, - self.$loadingMore[0] - ); + this.$results.on('scroll', this.loadMoreIfNeeded.bind(this)); + }; - if (self.loading || !isLoadMoreVisible) { - return; - } + InfiniteScroll.prototype.loadMoreIfNeeded = function () { + var isLoadMoreVisible = $.contains( + document.documentElement, + this.$loadingMore[0] + ); - var currentOffset = self.$results.offset().top + - self.$results.outerHeight(false); - var loadingMoreOffset = self.$loadingMore.offset().top + - self.$loadingMore.outerHeight(false); + if (this.loading || !isLoadMoreVisible) { + return; + } - if (currentOffset + 50 >= loadingMoreOffset) { - self.loadMore(); - } - }); + var currentOffset = this.$results.offset().top + + this.$results.outerHeight(false); + var loadingMoreOffset = this.$loadingMore.offset().top + + this.$loadingMore.outerHeight(false); + + if (currentOffset + 50 >= loadingMoreOffset) { + this.loadMore(); + } }; InfiniteScroll.prototype.loadMore = function () { @@ -4119,7 +4309,7 @@ S2.define('select2/dropdown/infiniteScroll',[ var $option = $( '
          • ' + 'role="option" aria-disabled="true">' ); var message = this.options.get('translations').get('loadingMore'); @@ -4137,7 +4327,7 @@ S2.define('select2/dropdown/attachBody',[ '../utils' ], function ($, Utils) { function AttachBody (decorated, $element, options) { - this.$dropdownParent = options.get('dropdownParent') || $(document.body); + this.$dropdownParent = $(options.get('dropdownParent') || document.body); decorated.call(this, $element, options); } @@ -4145,27 +4335,14 @@ S2.define('select2/dropdown/attachBody',[ AttachBody.prototype.bind = function (decorated, container, $container) { var self = this; - var setupResultsEvents = false; - decorated.call(this, container, $container); container.on('open', function () { self._showDropdown(); self._attachPositioningHandler(container); - if (!setupResultsEvents) { - setupResultsEvents = true; - - container.on('results:all', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - - container.on('results:append', function () { - self._positionDropdown(); - self._resizeDropdown(); - }); - } + // Must bind after the results handlers to ensure correct sizing + self._bindContainerResultHandlers(container); }); container.on('close', function () { @@ -4214,6 +4391,44 @@ S2.define('select2/dropdown/attachBody',[ this.$dropdownContainer.detach(); }; + AttachBody.prototype._bindContainerResultHandlers = + function (decorated, container) { + + // These should only be bound once + if (this._containerResultsHandlersBound) { + return; + } + + var self = this; + + container.on('results:all', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:append', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('results:message', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('select', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + container.on('unselect', function () { + self._positionDropdown(); + self._resizeDropdown(); + }); + + this._containerResultsHandlersBound = true; + }; + AttachBody.prototype._attachPositioningHandler = function (decorated, container) { var self = this; @@ -4224,14 +4439,14 @@ S2.define('select2/dropdown/attachBody',[ var $watchers = this.$container.parents().filter(Utils.hasScroll); $watchers.each(function () { - $(this).data('select2-scroll-position', { + Utils.StoreData(this, 'select2-scroll-position', { x: $(this).scrollLeft(), y: $(this).scrollTop() }); }); $watchers.on(scrollEvent, function (ev) { - var position = $(this).data('select2-scroll-position'); + var position = Utils.GetData(this, 'select2-scroll-position'); $(this).scrollTop(position.y); }); @@ -4290,16 +4505,26 @@ S2.define('select2/dropdown/attachBody',[ top: container.bottom }; - // Determine what the parent element is to use for calciulating the offset + // Determine what the parent element is to use for calculating the offset var $offsetParent = this.$dropdownParent; - // For statically positoned elements, we need to get the element + // For statically positioned elements, we need to get the element // that is determining the offset if ($offsetParent.css('position') === 'static') { $offsetParent = $offsetParent.offsetParent(); } - var parentOffset = $offsetParent.offset(); + var parentOffset = { + top: 0, + left: 0 + }; + + if ( + $.contains(document.body, $offsetParent[0]) || + $offsetParent[0].isConnected + ) { + parentOffset = $offsetParent.offset(); + } css.top -= parentOffset.top; css.left -= parentOffset.left; @@ -4396,8 +4621,8 @@ S2.define('select2/dropdown/minimumResultsForSearch',[ }); S2.define('select2/dropdown/selectOnClose',[ - -], function () { + '../utils' +], function (Utils) { function SelectOnClose () { } SelectOnClose.prototype.bind = function (decorated, container, $container) { @@ -4428,7 +4653,7 @@ S2.define('select2/dropdown/selectOnClose',[ return; } - var data = $highlightedResults.data('data'); + var data = Utils.GetData($highlightedResults[0], 'data'); // Don't re-select already selected resulte if ( @@ -4469,7 +4694,7 @@ S2.define('select2/dropdown/closeOnSelect',[ var originalEvent = evt.originalEvent; // Don't close if the control key is being held - if (originalEvent && originalEvent.ctrlKey) { + if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) { return; } @@ -4523,6 +4748,9 @@ S2.define('select2/i18n/en',[],function () { }, searching: function () { return 'Searching…'; + }, + removeAllItems: function () { + return 'Remove all items'; } }; }); @@ -4761,66 +4989,29 @@ S2.define('select2/defaults',[ ); } - if (typeof options.language === 'string') { - // Check if the language is specified with a region - if (options.language.indexOf('-') > 0) { - // Extract the region information if it is included - var languageParts = options.language.split('-'); - var baseLanguage = languageParts[0]; + // If the defaults were not previously applied from an element, it is + // possible for the language option to have not been resolved + options.language = this._resolveLanguage(options.language); - options.language = [options.language, baseLanguage]; - } else { - options.language = [options.language]; + // Always fall back to English since it will always be complete + options.language.push('en'); + + var uniqueLanguages = []; + + for (var l = 0; l < options.language.length; l++) { + var language = options.language[l]; + + if (uniqueLanguages.indexOf(language) === -1) { + uniqueLanguages.push(language); } } - if ($.isArray(options.language)) { - var languages = new Translation(); - options.language.push('en'); + options.language = uniqueLanguages; - var languageNames = options.language; - - for (var l = 0; l < languageNames.length; l++) { - var name = languageNames[l]; - var language = {}; - - try { - // Try to load it with the original name - language = Translation.loadPath(name); - } catch (e) { - try { - // If we couldn't load it, check if it wasn't the full path - name = this.defaults.amdLanguageBase + name; - language = Translation.loadPath(name); - } catch (ex) { - // The translation could not be loaded at all. Sometimes this is - // because of a configuration problem, other times this can be - // because of how Select2 helps load all possible translation files. - if (options.debug && window.console && console.warn) { - console.warn( - 'Select2: The language file for "' + name + '" could not be ' + - 'automatically loaded. A fallback will be used instead.' - ); - } - - continue; - } - } - - languages.extend(language); - } - - options.translations = languages; - } else { - var baseTranslation = Translation.loadPath( - this.defaults.amdLanguageBase + 'en' - ); - var customTranslation = new Translation(options.language); - - customTranslation.extend(baseTranslation); - - options.translations = customTranslation; - } + options.translations = this._processTranslations( + options.language, + options.debug + ); return options; }; @@ -4887,13 +5078,14 @@ S2.define('select2/defaults',[ debug: false, dropdownAutoWidth: false, escapeMarkup: Utils.escapeMarkup, - language: EnglishTranslation, + language: {}, matcher: matcher, minimumInputLength: 0, maximumInputLength: 0, maximumSelectionLength: 0, minimumResultsForSearch: 0, selectOnClose: false, + scrollAfterSelect: false, sorter: function (data) { return data; }, @@ -4908,6 +5100,103 @@ S2.define('select2/defaults',[ }; }; + Defaults.prototype.applyFromElement = function (options, $element) { + var optionLanguage = options.language; + var defaultLanguage = this.defaults.language; + var elementLanguage = $element.prop('lang'); + var parentLanguage = $element.closest('[lang]').prop('lang'); + + var languages = Array.prototype.concat.call( + this._resolveLanguage(elementLanguage), + this._resolveLanguage(optionLanguage), + this._resolveLanguage(defaultLanguage), + this._resolveLanguage(parentLanguage) + ); + + options.language = languages; + + return options; + }; + + Defaults.prototype._resolveLanguage = function (language) { + if (!language) { + return []; + } + + if ($.isEmptyObject(language)) { + return []; + } + + if ($.isPlainObject(language)) { + return [language]; + } + + var languages; + + if (!$.isArray(language)) { + languages = [language]; + } else { + languages = language; + } + + var resolvedLanguages = []; + + for (var l = 0; l < languages.length; l++) { + resolvedLanguages.push(languages[l]); + + if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) { + // Extract the region information if it is included + var languageParts = languages[l].split('-'); + var baseLanguage = languageParts[0]; + + resolvedLanguages.push(baseLanguage); + } + } + + return resolvedLanguages; + }; + + Defaults.prototype._processTranslations = function (languages, debug) { + var translations = new Translation(); + + for (var l = 0; l < languages.length; l++) { + var languageData = new Translation(); + + var language = languages[l]; + + if (typeof language === 'string') { + try { + // Try to load it with the original name + languageData = Translation.loadPath(language); + } catch (e) { + try { + // If we couldn't load it, check if it wasn't the full path + language = this.defaults.amdLanguageBase + language; + languageData = Translation.loadPath(language); + } catch (ex) { + // The translation could not be loaded at all. Sometimes this is + // because of a configuration problem, other times this can be + // because of how Select2 helps load all possible translation files + if (debug && window.console && console.warn) { + console.warn( + 'Select2: The language file for "' + language + '" could ' + + 'not be automatically loaded. A fallback will be used instead.' + ); + } + } + } + } else if ($.isPlainObject(language)) { + languageData = new Translation(language); + } else { + languageData = language; + } + + translations.extend(languageData); + } + + return translations; + }; + Defaults.prototype.set = function (key, value) { var camelKey = $.camelCase(key); @@ -4916,7 +5205,7 @@ S2.define('select2/defaults',[ var convertedData = Utils._convertData(data); - $.extend(this.defaults, convertedData); + $.extend(true, this.defaults, convertedData); }; var defaults = new Defaults(); @@ -4937,6 +5226,10 @@ S2.define('select2/options',[ this.fromElement($element); } + if ($element != null) { + this.options = Defaults.applyFromElement(this.options, $element); + } + this.options = Defaults.apply(this.options); if ($element && $element.is('input')) { @@ -4960,14 +5253,6 @@ S2.define('select2/options',[ this.options.disabled = $e.prop('disabled'); } - if (this.options.language == null) { - if ($e.prop('lang')) { - this.options.language = $e.prop('lang').toLowerCase(); - } else if ($e.closest('[lang]').prop('lang')) { - this.options.language = $e.closest('[lang]').prop('lang'); - } - } - if (this.options.dir == null) { if ($e.prop('dir')) { this.options.dir = $e.prop('dir'); @@ -4981,7 +5266,7 @@ S2.define('select2/options',[ $e.prop('disabled', this.options.disabled); $e.prop('multiple', this.options.multiple); - if ($e.data('select2Tags')) { + if (Utils.GetData($e[0], 'select2Tags')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-select2-tags` attribute has been changed to ' + @@ -4990,11 +5275,11 @@ S2.define('select2/options',[ ); } - $e.data('data', $e.data('select2Tags')); - $e.data('tags', true); + Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags')); + Utils.StoreData($e[0], 'tags', true); } - if ($e.data('ajaxUrl')) { + if (Utils.GetData($e[0], 'ajaxUrl')) { if (this.options.debug && window.console && console.warn) { console.warn( 'Select2: The `data-ajax-url` attribute has been changed to ' + @@ -5003,21 +5288,45 @@ S2.define('select2/options',[ ); } - $e.attr('ajax--url', $e.data('ajaxUrl')); - $e.data('ajax--url', $e.data('ajaxUrl')); + $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl')); + Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl')); } var dataset = {}; + function upperCaseLetter(_, letter) { + return letter.toUpperCase(); + } + + // Pre-load all of the attributes which are prefixed with `data-` + for (var attr = 0; attr < $e[0].attributes.length; attr++) { + var attributeName = $e[0].attributes[attr].name; + var prefix = 'data-'; + + if (attributeName.substr(0, prefix.length) == prefix) { + // Get the contents of the attribute after `data-` + var dataName = attributeName.substring(prefix.length); + + // Get the data contents from the consistent source + // This is more than likely the jQuery data helper + var dataValue = Utils.GetData($e[0], dataName); + + // camelCase the attribute name to match the spec + var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter); + + // Store the data attribute contents into the dataset since + dataset[camelDataName] = dataValue; + } + } + // Prefer the element's `dataset` attribute if it exists // jQuery 1.x does not correctly handle data attributes with multiple dashes if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) { - dataset = $.extend(true, {}, $e[0].dataset, $e.data()); - } else { - dataset = $e.data(); + dataset = $.extend(true, {}, $e[0].dataset, dataset); } - var data = $.extend(true, {}, dataset); + // Prefer our internal data cache if it exists + var data = $.extend(true, {}, Utils.GetData($e[0]), dataset); data = Utils._convertData(data); @@ -5054,8 +5363,8 @@ S2.define('select2/core',[ './keys' ], function ($, Options, Utils, KEYS) { var Select2 = function ($element, options) { - if ($element.data('select2') != null) { - $element.data('select2').destroy(); + if (Utils.GetData($element[0], 'select2') != null) { + Utils.GetData($element[0], 'select2').destroy(); } this.$element = $element; @@ -5071,7 +5380,7 @@ S2.define('select2/core',[ // Set up the tabindex var tabindex = $element.attr('tabindex') || 0; - $element.data('old-tabindex', tabindex); + Utils.StoreData($element[0], 'old-tabindex', tabindex); $element.attr('tabindex', '-1'); // Set up containers and adapters @@ -5132,6 +5441,9 @@ S2.define('select2/core',[ // Synchronize any monitored attributes this._syncAttributes(); + Utils.StoreData($element[0], 'select2', this); + + // Ensure backwards compatibility with $element.data('select2'). $element.data('select2', this); }; @@ -5208,6 +5520,12 @@ S2.define('select2/core',[ return null; } + if (method == 'computedstyle') { + var computedStyle = window.getComputedStyle($element[0]); + + return computedStyle.width; + } + return method; }; @@ -5248,8 +5566,8 @@ S2.define('select2/core',[ if (observer != null) { this._observer = new observer(function (mutations) { - $.each(mutations, self._syncA); - $.each(mutations, self._syncS); + self._syncA(); + self._syncS(null, mutations); }); this._observer.observe(this.$element[0], { attributes: true, @@ -5371,7 +5689,7 @@ S2.define('select2/core',[ if (self.isOpen()) { if (key === KEYS.ESC || key === KEYS.TAB || (key === KEYS.UP && evt.altKey)) { - self.close(); + self.close(evt); evt.preventDefault(); } else if (key === KEYS.ENTER) { @@ -5405,7 +5723,7 @@ S2.define('select2/core',[ Select2.prototype._syncAttributes = function () { this.options.set('disabled', this.$element.prop('disabled')); - if (this.options.get('disabled')) { + if (this.isDisabled()) { if (this.isOpen()) { this.close(); } @@ -5416,7 +5734,7 @@ S2.define('select2/core',[ } }; - Select2.prototype._syncSubtree = function (evt, mutations) { + Select2.prototype._isChangeMutation = function (evt, mutations) { var changed = false; var self = this; @@ -5444,7 +5762,22 @@ S2.define('select2/core',[ } } else if (mutations.removedNodes && mutations.removedNodes.length > 0) { changed = true; + } else if ($.isArray(mutations)) { + $.each(mutations, function(evt, mutation) { + if (self._isChangeMutation(evt, mutation)) { + // We've found a change mutation. + // Let's escape from the loop and continue + changed = true; + return false; + } + }); } + return changed; + }; + + Select2.prototype._syncSubtree = function (evt, mutations) { + var changed = this._isChangeMutation(evt, mutations); + var self = this; // Only re-pull the data if we think there is a change if (changed) { @@ -5466,7 +5799,8 @@ S2.define('select2/core',[ 'open': 'opening', 'close': 'closing', 'select': 'selecting', - 'unselect': 'unselecting' + 'unselect': 'unselecting', + 'clear': 'clearing' }; if (args === undefined) { @@ -5494,7 +5828,7 @@ S2.define('select2/core',[ }; Select2.prototype.toggleDropdown = function () { - if (this.options.get('disabled')) { + if (this.isDisabled()) { return; } @@ -5510,15 +5844,40 @@ S2.define('select2/core',[ return; } + if (this.isDisabled()) { + return; + } + this.trigger('query', {}); }; - Select2.prototype.close = function () { + Select2.prototype.close = function (evt) { if (!this.isOpen()) { return; } - this.trigger('close', {}); + this.trigger('close', { originalEvent : evt }); + }; + + /** + * Helper method to abstract the "enabled" (not "disabled") state of this + * object. + * + * @return {true} if the instance is not disabled. + * @return {false} if the instance is disabled. + */ + Select2.prototype.isEnabled = function () { + return !this.isDisabled(); + }; + + /** + * Helper method to abstract the "disabled" state of this object. + * + * @return {true} if the disabled option is true. + * @return {false} if the disabled option is false. + */ + Select2.prototype.isDisabled = function () { + return this.options.get('disabled'); }; Select2.prototype.isOpen = function () { @@ -5595,7 +5954,7 @@ S2.define('select2/core',[ }); } - this.$element.val(newVal).trigger('change'); + this.$element.val(newVal).trigger('input').trigger('change'); }; Select2.prototype.destroy = function () { @@ -5621,10 +5980,12 @@ S2.define('select2/core',[ this._syncS = null; this.$element.off('.select2'); - this.$element.attr('tabindex', this.$element.data('old-tabindex')); + this.$element.attr('tabindex', + Utils.GetData(this.$element[0], 'old-tabindex')); this.$element.removeClass('select2-hidden-accessible'); this.$element.attr('aria-hidden', 'false'); + Utils.RemoveData(this.$element[0]); this.$element.removeData('select2'); this.dataAdapter.destroy(); @@ -5652,7 +6013,7 @@ S2.define('select2/core',[ this.$container.addClass('select2-container--' + this.options.get('theme')); - $container.data('element', this.$element); + Utils.StoreData($container[0], 'element', this.$element); return $container; }; @@ -5672,8 +6033,9 @@ S2.define('jquery.select2',[ 'jquery-mousewheel', './select2/core', - './select2/defaults' -], function ($, _, Select2, Defaults) { + './select2/defaults', + './select2/utils' +], function ($, _, Select2, Defaults, Utils) { if ($.fn.select2 == null) { // All methods that should return the element var thisMethods = ['open', 'close', 'destroy']; @@ -5694,7 +6056,7 @@ S2.define('jquery.select2',[ var args = Array.prototype.slice.call(arguments, 1); this.each(function () { - var instance = $(this).data('select2'); + var instance = Utils.GetData(this, 'select2'); if (instance == null && window.console && console.error) { console.error( diff --git a/InvenTree/InvenTree/static/select2/js/select2.min.js b/InvenTree/InvenTree/static/select2/js/select2.min.js new file mode 100644 index 0000000000..e421426434 --- /dev/null +++ b/InvenTree/InvenTree/static/select2/js/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s,f,g,m,v,y,_,i,a,b;function w(e,t){return i.call(e,t)}function l(e,t){var n,r,i,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&b.test(e[s])&&(e[s]=e[s].replace(b,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},i.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},i.__cache={};var n=0;return i.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},i.StoreData=function(e,t,n){var r=i.GetUniqueElementId(e);i.__cache[r]||(i.__cache[r]={}),i.__cache[r][t]=n},i.GetData=function(e,t){var n=i.GetUniqueElementId(e);return t?i.__cache[n]&&null!=i.__cache[n][t]?i.__cache[n][t]:o(e).data(t):i.__cache[n]},i.RemoveData=function(e){var t=i.GetUniqueElementId(e);null!=i.__cache[t]&&delete i.__cache[t],e.removeAttribute("data-select2-id")},i}),e.define("select2/results",["jquery","./utils"],function(h,f){function r(e,t,n){this.$element=e,this.data=n,this.options=t,r.__super__.constructor.call(this)}return f.Extend(r,f.Observable),r.prototype.render=function(){var e=h('
              ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},r.prototype.clear=function(){this.$results.empty()},r.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h(''),r=this.options.get("translations").get(e.message);n.append(t(r(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},r.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},r.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},r.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var r=n-1;0===e.length&&(r=0);var i=t.eq(r);i.trigger("mouseenter");var o=l.$results.offset().top,s=i.offset().top,a=l.$results.scrollTop()+(s-o);0===r?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var r=t.eq(n);r.trigger("mouseenter");var i=l.$results.offset().top+l.$results.outerHeight(!1),o=r.offset().top+r.outerHeight(!1),s=l.$results.scrollTop()+o-i;0===n?l.$results.scrollTop(0):ithis.$results.outerHeight()||o<0)&&this.$results.scrollTop(i)}},r.prototype.template=function(e,t){var n=this.options.get("templateResult"),r=this.options.get("escapeMarkup"),i=n(e,t);null==i?t.style.display="none":"string"==typeof i?t.innerHTML=r(i):h(t).append(i)},r}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,r,i){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return r.Extend(o,r.Observable),o.prototype.render=function(){var e=n('');return this._tabindex=0,null!=r.GetData(this.$element[0],"old-tabindex")?this._tabindex=r.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,r=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",r),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&r.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o.prototype.isEnabled=function(){return!this.isDisabled()},o.prototype.isDisabled=function(){return this.options.get("disabled")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,r){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var r=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",r).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",r),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),r=this.display(t,n);n.empty().append(r);var i=t.title||t.text;i?n.attr("title",i):n.removeAttr("title")}else this.clear()},i}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('
                '),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.isDisabled()){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('
              • ×
              • ')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n×');a.StoreData(r[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(r)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(r,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=r('');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),t.on("open",function(){r.$search.attr("aria-controls",i),r.$search.trigger("focus")}),t.on("close",function(){r.$search.val(""),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.trigger("focus")}),t.on("enable",function(){r.$search.prop("disabled",!1),r._transferTabIndex()}),t.on("disable",function(){r.$search.prop("disabled",!0)}),t.on("focus",function(e){r.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){r.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){r._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===r.$search.val()){var t=r.$searchContainer.prev(".select2-selection__choice");if(0this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(){r._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var r=this;this._checkIfMaximumSelected(function(){e.call(r,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var r=this;this.current(function(e){var t=null!=e?e.length:0;0=r.maximumSelectionLength?r.trigger("results:message",{message:"maximumSelected",args:{maximum:r.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){r.handleSearch(e)}),t.on("open",function(){r.$search.attr("tabindex",0),r.$search.attr("aria-controls",i),r.$search.trigger("focus"),window.setTimeout(function(){r.$search.trigger("focus")},0)}),t.on("close",function(){r.$search.attr("tabindex",-1),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.val(""),r.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||r.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(r.showSearch(e)?r.$searchContainer.removeClass("select2-search--hide"):r.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,r){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,r)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),r=t.length-1;0<=r;r--){var i=t[r];this.placeholder.id===i.id&&n.splice(r,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,r){this.lastParams={},e.call(this,t,n,r),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("query",function(e){r.lastParams=e,r.loading=!0}),t.on("query:append",function(e){r.lastParams=e,r.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
              • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("open",function(){r._showDropdown(),r._attachPositioningHandler(t),r._bindContainerResultHandlers(t)}),t.on("close",function(){r._hideDropdown(),r._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f(""),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,r="scroll.select2."+t.id,i="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(r,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(r+" "+i+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,r="resize.select2."+t.id,i="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+r+" "+i)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),r=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=i.top,o.bottom=i.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+s,d={left:i.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(r="below"),u||!c||t?!c&&u&&t&&(r="below"):r="above",("above"==r||t&&"below"!==r)&&(d.top=o.top-h.top-s),null!=r&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+r),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+r)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,r){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,r)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,r=0;r');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("jquery-mousewheel",["jquery"],function(e){return e}),e.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,o,t,s){if(null==i.fn.select2){var a=["open","close","destroy"];i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new o(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,r=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=s.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,r)}),-1 2021-07-19 + - Refactors the API interface for SupplierPart and ManufacturerPart models + - ManufacturerPart objects can no longer be created via the SupplierPart API endpoint + +v7 -> 2021-07-03 + - Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716 + - API OPTIONS endpoints provide comprehensive field metedata + - Multiple new API endpoints added for database models v6 -> 2021-06-23 - Part and Company images can now be directly uploaded via the REST API diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 17caeb872d..4b559642ca 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -12,7 +12,6 @@ from django.utils.translation import gettext_lazy as _ from django.template.loader import render_to_string from django.http import HttpResponse, JsonResponse, HttpResponseRedirect from django.urls import reverse_lazy -from django.conf import settings from django.contrib.auth.mixins import PermissionRequiredMixin @@ -21,6 +20,7 @@ from django.views.generic import ListView, DetailView, CreateView, FormView, Del from django.views.generic.base import RedirectView, TemplateView from djmoney.contrib.exchange.models import ExchangeBackend, Rate +from common.settings import currency_code_default, currency_codes from part.models import Part, PartCategory from stock.models import StockLocation, StockItem @@ -820,8 +820,8 @@ class CurrencySettingsView(TemplateView): ctx = super().get_context_data(**kwargs).copy() ctx['settings'] = InvenTreeSetting.objects.all().order_by('key') - ctx["base_currency"] = settings.BASE_CURRENCY - ctx["currencies"] = settings.CURRENCIES + ctx["base_currency"] = currency_code_default() + ctx["currencies"] = currency_codes ctx["rates"] = Rate.objects.filter(backend="InvenTreeExchange") diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 1cb973fe05..47edb55545 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -5,17 +5,50 @@ JSON API for the Build app # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django_filters.rest_framework import DjangoFilterBackend +from django.conf.urls import url, include + from rest_framework import filters from rest_framework import generics -from django.conf.urls import url, include +from django_filters.rest_framework import DjangoFilterBackend +from django_filters import rest_framework as rest_filters +from InvenTree.api import AttachmentMixin from InvenTree.helpers import str2bool, isNull from InvenTree.status_codes import BuildStatus -from .models import Build, BuildItem -from .serializers import BuildSerializer, BuildItemSerializer +from .models import Build, BuildItem, BuildOrderAttachment +from .serializers import BuildAttachmentSerializer, BuildSerializer, BuildItemSerializer + + +class BuildFilter(rest_filters.FilterSet): + """ + Custom filterset for BuildList API endpoint + """ + + status = rest_filters.NumberFilter(label='Status') + + active = rest_filters.BooleanFilter(label='Build is active', method='filter_active') + + def filter_active(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.filter(status__in=BuildStatus.ACTIVE_CODES) + else: + queryset = queryset.exclude(status__in=BuildStatus.ACTIVE_CODES) + + return queryset + + overdue = rest_filters.BooleanFilter(label='Build is overdue', method='filter_overdue') + + def filter_overdue(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.filter(Build.OVERDUE_FILTER) + else: + queryset = queryset.exclude(Build.OVERDUE_FILTER) + + return queryset class BuildList(generics.ListCreateAPIView): @@ -27,6 +60,7 @@ class BuildList(generics.ListCreateAPIView): queryset = Build.objects.all() serializer_class = BuildSerializer + filterset_class = BuildFilter filter_backends = [ DjangoFilterBackend, @@ -34,10 +68,6 @@ class BuildList(generics.ListCreateAPIView): filters.OrderingFilter, ] - filter_fields = [ - 'sales_order', - ] - ordering_fields = [ 'reference', 'part__name', @@ -46,6 +76,8 @@ class BuildList(generics.ListCreateAPIView): 'target_date', 'completion_date', 'quantity', + 'issued_by', + 'responsible', ] search_fields = [ @@ -78,6 +110,12 @@ class BuildList(generics.ListCreateAPIView): if parent is not None: queryset = queryset.filter(parent=parent) + # Filter by sales_order + sales_order = params.get('sales_order', None) + + if sales_order is not None: + queryset = queryset.filter(sales_order=sales_order) + # Filter by "ancestor" builds ancestor = params.get('ancestor', None) @@ -94,34 +132,6 @@ class BuildList(generics.ListCreateAPIView): except (ValueError, Build.DoesNotExist): pass - # Filter by build status? - status = params.get('status', None) - - if status is not None: - queryset = queryset.filter(status=status) - - # Filter by "pending" status - active = params.get('active', None) - - if active is not None: - active = str2bool(active) - - if active: - queryset = queryset.filter(status__in=BuildStatus.ACTIVE_CODES) - else: - queryset = queryset.exclude(status__in=BuildStatus.ACTIVE_CODES) - - # Filter by "overdue" status? - overdue = params.get('overdue', None) - - if overdue is not None: - overdue = str2bool(overdue) - - if overdue: - queryset = queryset.filter(Build.OVERDUE_FILTER) - else: - queryset = queryset.exclude(Build.OVERDUE_FILTER) - # Filter by associated part? part = params.get('part', None) @@ -226,14 +236,48 @@ class BuildItemList(generics.ListCreateAPIView): ] -build_item_api_urls = [ - url('^.*$', BuildItemList.as_view(), name='api-build-item-list'), -] +class BuildAttachmentList(generics.ListCreateAPIView, AttachmentMixin): + """ + API endpoint for listing (and creating) BuildOrderAttachment objects + """ + + queryset = BuildOrderAttachment.objects.all() + serializer_class = BuildAttachmentSerializer + + filter_backends = [ + DjangoFilterBackend, + ] + + filter_fields = [ + 'build', + ] + + +class BuildAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for a BuildOrderAttachment object + """ + + queryset = BuildOrderAttachment.objects.all() + serializer_class = BuildAttachmentSerializer + build_api_urls = [ - url(r'^item/', include(build_item_api_urls)), + # Attachments + url(r'^attachment/', include([ + url(r'^(?P\d+)/', BuildAttachmentDetail.as_view(), name='api-build-attachment-detail'), + url('^.*$', BuildAttachmentList.as_view(), name='api-build-attachment-list'), + ])), + + # Build Items + url(r'^item/', include([ + url('^.*$', BuildItemList.as_view(), name='api-build-item-list') + ])), + + # Build Detail url(r'^(?P\d+)/', BuildDetail.as_view(), name='api-build-detail'), + # Build List url(r'^.*$', BuildList.as_view(), name='api-build-list'), ] diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py index e60df22c21..e2ca7c3f75 100644 --- a/InvenTree/build/forms.py +++ b/InvenTree/build/forms.py @@ -15,7 +15,7 @@ from InvenTree.fields import DatePickerFormField from InvenTree.status_codes import StockStatus -from .models import Build, BuildItem, BuildOrderAttachment +from .models import Build, BuildItem from stock.models import StockLocation, StockItem @@ -275,17 +275,3 @@ class EditBuildItemForm(HelperForm): 'quantity', 'install_into', ] - - -class EditBuildAttachmentForm(HelperForm): - """ - Form for creating / editing a BuildAttachment object - """ - - class Meta: - model = BuildOrderAttachment - fields = [ - 'build', - 'attachment', - 'comment' - ] diff --git a/InvenTree/build/migrations/0029_auto_20210601_1525.py b/InvenTree/build/migrations/0029_auto_20210601_1525.py index e8b2d58947..fa6bab6b26 100644 --- a/InvenTree/build/migrations/0029_auto_20210601_1525.py +++ b/InvenTree/build/migrations/0029_auto_20210601_1525.py @@ -1,8 +1,13 @@ # Generated by Django 3.2 on 2021-06-01 05:25 +import logging + from django.db import migrations +logger = logging.getLogger('inventree') + + def assign_bom_items(apps, schema_editor): """ Run through existing BuildItem objects, @@ -13,7 +18,7 @@ def assign_bom_items(apps, schema_editor): BomItem = apps.get_model('part', 'bomitem') Part = apps.get_model('part', 'part') - print("Assigning BomItems to existing BuildItem objects") + logger.info("Assigning BomItems to existing BuildItem objects") count_valid = 0 count_total = 0 @@ -41,7 +46,7 @@ def assign_bom_items(apps, schema_editor): pass if count_total > 0: - print(f"Assigned BomItem for {count_valid}/{count_total} entries") + logger.info(f"Assigned BomItem for {count_valid}/{count_total} entries") def unassign_bom_items(apps, schema_editor): diff --git a/InvenTree/build/migrations/0030_alter_build_reference.py b/InvenTree/build/migrations/0030_alter_build_reference.py new file mode 100644 index 0000000000..75f43c77dc --- /dev/null +++ b/InvenTree/build/migrations/0030_alter_build_reference.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.4 on 2021-07-08 14:14 + +import InvenTree.validators +import build.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('build', '0029_auto_20210601_1525'), + ] + + operations = [ + migrations.AlterField( + model_name='build', + name='reference', + field=models.CharField(default=build.models.get_next_build_number, help_text='Build Order Reference', max_length=64, unique=True, validators=[InvenTree.validators.validate_build_order_reference], verbose_name='Reference'), + ), + ] diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index fad5a2934d..5f8af9096b 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -21,6 +21,7 @@ from django.core.validators import MinValueValidator from markdownx.models import MarkdownxField from mptt.models import MPTTModel, TreeForeignKey +from mptt.exceptions import InvalidMove from InvenTree.status_codes import BuildStatus, StockStatus, StockHistoryCode from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode @@ -37,6 +38,35 @@ from part import models as PartModels from users import models as UserModels +def get_next_build_number(): + """ + Returns the next available BuildOrder reference number + """ + + if Build.objects.count() == 0: + return + + build = Build.objects.exclude(reference=None).last() + + attempts = set([build.reference]) + + reference = build.reference + + while 1: + reference = increment(reference) + + if reference in attempts: + # Escape infinite recursion + return reference + + if Build.objects.filter(reference=reference).exists(): + attempts.add(reference) + else: + break + + return reference + + class Build(MPTTModel): """ A Build object organises the creation of new StockItem objects from other existing StockItem objects. @@ -61,6 +91,19 @@ class Build(MPTTModel): """ OVERDUE_FILTER = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date()) + + @staticmethod + def get_api_url(): + return reverse('api-build-list') + + def save(self, *args, **kwargs): + + try: + super().save(*args, **kwargs) + except InvalidMove: + raise ValidationError({ + 'parent': _('Invalid choice for parent build'), + }) class Meta: verbose_name = _("Build Order") @@ -126,6 +169,7 @@ class Build(MPTTModel): blank=False, help_text=_('Build Order Reference'), verbose_name=_('Reference'), + default=get_next_build_number, validators=[ validate_build_order_reference ] @@ -1117,6 +1161,10 @@ class BuildItem(models.Model): quantity: Number of units allocated """ + @staticmethod + def get_api_url(): + return reverse('api-build-item-list') + def get_absolute_url(self): # TODO - Fix! return '/build/item/{pk}/'.format(pk=self.id) diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index d8573cfa70..5c0fced884 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -10,13 +10,14 @@ from django.db.models import BooleanField from rest_framework import serializers -from InvenTree.serializers import InvenTreeModelSerializer +from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializerField, UserSerializerBrief from stock.serializers import StockItemSerializerBrief from stock.serializers import LocationSerializer from part.serializers import PartSerializer, PartBriefSerializer +from users.serializers import OwnerSerializer -from .models import Build, BuildItem +from .models import Build, BuildItem, BuildOrderAttachment class BuildSerializer(InvenTreeModelSerializer): @@ -31,6 +32,10 @@ class BuildSerializer(InvenTreeModelSerializer): overdue = serializers.BooleanField(required=False, read_only=True) + issued_by_detail = UserSerializerBrief(source='issued_by', read_only=True) + + responsible_detail = OwnerSerializer(source='responsible', read_only=True) + @staticmethod def annotate_queryset(queryset): """ @@ -57,7 +62,7 @@ class BuildSerializer(InvenTreeModelSerializer): return queryset def __init__(self, *args, **kwargs): - part_detail = kwargs.pop('part_detail', False) + part_detail = kwargs.pop('part_detail', True) super().__init__(*args, **kwargs) @@ -70,9 +75,12 @@ class BuildSerializer(InvenTreeModelSerializer): 'pk', 'url', 'title', + 'batch', 'creation_date', 'completed', 'completion_date', + 'destination', + 'parent', 'part', 'part_detail', 'overdue', @@ -82,8 +90,13 @@ class BuildSerializer(InvenTreeModelSerializer): 'status', 'status_text', 'target_date', + 'take_from', 'notes', 'link', + 'issued_by', + 'issued_by_detail', + 'responsible', + 'responsible_detail', ] read_only_fields = [ @@ -143,3 +156,26 @@ class BuildItemSerializer(InvenTreeModelSerializer): 'stock_item_detail', 'quantity' ] + + +class BuildAttachmentSerializer(InvenTreeModelSerializer): + """ + Serializer for a BuildAttachment + """ + + attachment = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = BuildOrderAttachment + + fields = [ + 'pk', + 'build', + 'attachment', + 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', + ] diff --git a/InvenTree/build/templates/build/allocate.html b/InvenTree/build/templates/build/allocate.html deleted file mode 100644 index de07614c8e..0000000000 --- a/InvenTree/build/templates/build/allocate.html +++ /dev/null @@ -1,101 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block page_title %} -{% inventree_title %} | {% trans "Allocate Parts" %} -{% endblock %} - -{% block menubar %} -{% include "build/navbar.html" with tab='allocate' %} -{% endblock %} - -{% block heading %} -{% trans "Allocate Stock to Build" %} -{% endblock %} - -{% block details %} -{% if build.has_untracked_bom_items %} -{% if build.active %} -
                - - - -
                -{% if build.areUntrackedPartsFullyAllocated %} -
                - {% trans "Untracked stock has been fully allocated for this Build Order" %} -
                -{% else %} -
                - {% trans "Untracked stock has not been fully allocated for this Build Order" %} -
                -{% endif %} -{% endif %} -
                -{% else %} -
                - {% trans "This Build Order does not have any associated untracked BOM items" %} -
                -{% endif %} -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - var buildInfo = { - pk: {{ build.pk }}, - quantity: {{ build.quantity }}, - completed: {{ build.completed }}, - part: {{ build.part.pk }}, - }; - - {% if build.has_untracked_bom_items %} - // Load allocation table for un-tracked parts - loadBuildOutputAllocationTable(buildInfo, null); - {% endif %} - - function reloadTable() { - $('#allocation-table-untracked').bootstrapTable('refresh'); - } - - {% if build.active %} - $("#btn-auto-allocate").on('click', function() { - launchModalForm( - "{% url 'build-auto-allocate' build.id %}", - { - success: reloadTable, - } - ); - }); - - $('#btn-unallocate').on('click', function() { - launchModalForm( - "{% url 'build-unallocate' build.id %}", - { - success: reloadTable, - } - ); - }); - - $("#btn-order-parts").click(function() { - launchModalForm("/order/purchase-order/order-parts/", { - data: { - build: {{ build.id }}, - }, - }); - }); - - {% endif %} - -{% endblock %} - \ No newline at end of file diff --git a/InvenTree/build/templates/build/attachments.html b/InvenTree/build/templates/build/attachments.html deleted file mode 100644 index 8546ab42f5..0000000000 --- a/InvenTree/build/templates/build/attachments.html +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "build/build_base.html" %} - -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "build/navbar.html" with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Attachments" %} -{% endblock %} - -{% block details %} -{% include "attachment_table.html" with attachments=build.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - '{% url "build-attachment-create" %}', - { - data: { - build: {{ build.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } -); - -// Callback for creating a new attachment -$('#new-attachment').click(function() { - launchModalForm( - '{% url "build-attachment-create" %}', - { - reload: true, - data: { - build: {{ build.pk }}, - } - } - ); -}); - -// Callback for editing an attachment -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var pk = $(this).attr('pk'); - - var url = `/build/attachment/${pk}/edit/`; - - launchModalForm( - url, - { - reload: true, - } - ); -}); - -// Callback for deleting an attachment -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var pk = $(this).attr('pk'); - - var url = `/build/attachment/${pk}/delete/`; - - launchModalForm( - url, - { - reload: true, - } - ); -}); - -$("#attachment-table").inventreeTable({}); - -{% endblock %} diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 2376daf0cf..5770777d28 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -126,7 +126,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Part" %} - {{ build.part.full_name }} + {{ build.part.full_name }} @@ -196,10 +196,7 @@ src="{% static 'img/blank_image.png' %}" }); $("#build-edit").click(function () { - launchModalForm("{% url 'build-edit' build.id %}", - { - reload: true - }); + editBuildOrder({{ build.pk }}); }); $("#build-cancel").click(function() { @@ -241,4 +238,10 @@ src="{% static 'img/blank_image.png' %}" ); }); + attachNavCallbacks({ + name: 'buildorder', + default: 'details' + }); + + {% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/build_children.html b/InvenTree/build/templates/build/build_children.html deleted file mode 100644 index 3bab257d81..0000000000 --- a/InvenTree/build/templates/build/build_children.html +++ /dev/null @@ -1,40 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "build/navbar.html" with tab="children" %} -{% endblock %} - -{% block heading %} -{% trans "Child Build Orders" %} -{% endblock %} - - -{% block details %} -
                -
                -
                - -
                -
                - -
                - -
                - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadBuildTable($('#sub-build-table'), { - url: '{% url "api-build-list" %}', - filterTarget: "#filter-list-sub-build", - params: { - ancestor: {{ build.pk }}, - } -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/build_output.html b/InvenTree/build/templates/build/build_output.html deleted file mode 100644 index 00d7c5d5d2..0000000000 --- a/InvenTree/build/templates/build/build_output.html +++ /dev/null @@ -1,103 +0,0 @@ -{% extends "build/build_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "build/navbar.html" with tab='output' %} -{% endblock %} - -{% block content_panels %} - -{% if not build.is_complete %} -
                -
                -

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

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

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

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

                {% trans "Build Details" %}

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

                {% trans "Child Build Orders" %}

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

                {% trans "Allocate Stock to Build" %}

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

                {% trans "Incomplete Build Outputs" %}

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

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

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

                {% trans "Attachments" %}

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

                {% trans "Build Notes" %}

                +
                +
                +
                + +
                +
                +
                +
                +
                + {% if build.notes %} + {{ build.notes | markdownify }} + {% endif %} +
                +
                + + {% endblock %} + +{% block js_ready %} +{{ block.super }} + +$('#btn-create-output').click(function() { + launchModalForm('{% url "build-output-create" build.id %}', + { + reload: true, + } + ); +}); + +loadStockTable($("#build-stock-table"), { + params: { + location_detail: true, + part_detail: true, + build: {{ build.id }}, + }, + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", +}); + +var buildInfo = { + pk: {{ build.pk }}, + quantity: {{ build.quantity }}, + completed: {{ build.completed }}, + part: {{ build.part.pk }}, +}; + +{% for item in build.incomplete_outputs %} +// Get the build output as a javascript object +inventreeGet('{% url 'api-stock-detail' item.pk %}', {}, + { + success: function(response) { + loadBuildOutputAllocationTable(buildInfo, response); + } + } +); +{% endfor %} + +loadBuildTable($('#sub-build-table'), { + url: '{% url "api-build-list" %}', + filterTarget: "#filter-list-sub-build", + params: { + ancestor: {{ build.pk }}, + } +}); + +enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-build-attachment-list" %}', + { + data: { + build: {{ build.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } + } +); + +// Callback for creating a new attachment +$('#new-attachment').click(function() { + + constructForm('{% url "api-build-attachment-list" %}', { + fields: { + attachment: {}, + comment: {}, + build: { + value: {{ build.pk }}, + hidden: true, + } + }, + method: 'POST', + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}', + }); +}); + +loadAttachmentTable( + '{% url "api-build-attachment-list" %}', + { + filters: { + build: {{ build.pk }}, + }, + onEdit: function(pk) { + var url = `/api/build/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + + constructForm(`/api/build/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } +); + +$('#edit-notes').click(function() { + constructForm('{% url "api-build-detail" build.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); +}); + +var buildInfo = { + pk: {{ build.pk }}, + quantity: {{ build.quantity }}, + completed: {{ build.completed }}, + part: {{ build.part.pk }}, +}; + +{% if build.has_untracked_bom_items %} +// Load allocation table for un-tracked parts +loadBuildOutputAllocationTable(buildInfo, null); +{% endif %} + +function reloadTable() { + $('#allocation-table-untracked').bootstrapTable('refresh'); +} + +{% if build.active %} +$("#btn-auto-allocate").on('click', function() { + launchModalForm( + "{% url 'build-auto-allocate' build.id %}", + { + success: reloadTable, + } + ); +}); + +$('#btn-unallocate').on('click', function() { + launchModalForm( + "{% url 'build-unallocate' build.id %}", + { + success: reloadTable, + } + ); +}); + +$("#btn-order-parts").click(function() { + launchModalForm("/order/purchase-order/order-parts/", { + data: { + build: {{ build.id }}, + }, + }); +}); + +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/navbar.html b/InvenTree/build/templates/build/navbar.html index e6d2e644ce..e4c4fe4e50 100644 --- a/InvenTree/build/templates/build/navbar.html +++ b/InvenTree/build/templates/build/navbar.html @@ -9,46 +9,45 @@ -
              • - +
              • + {% trans "Details" %}
              • {% if build.active %} - -
              • - +
              • + {% trans "Allocate Stock" %}
              • {% endif %} -
              • - +
              • + {% trans "Build Outputs" %}
              • -
              • - +
              • + {% trans "Child Builds" %}
              • -
              • - +
              • + {% trans "Attachments" %}
              • -
              • - +
              • + {% trans "Notes" %} diff --git a/InvenTree/build/templates/build/notes.html b/InvenTree/build/templates/build/notes.html deleted file mode 100644 index 8eff2eff10..0000000000 --- a/InvenTree/build/templates/build/notes.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "build/build_base.html" %} - -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "build/navbar.html" with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Build Notes" %} -{% if roles.build.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
                -
                - {% csrf_token %} - - {{ form }} -
                - - -
                - -{{ form.media }} - -{% else %} - -{{ build.notes | markdownify }} -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'build-notes' build.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/test_build.py b/InvenTree/build/test_build.py index a3b69646dd..b572feb14b 100644 --- a/InvenTree/build/test_build.py +++ b/InvenTree/build/test_build.py @@ -5,10 +5,11 @@ from django.test import TestCase from django.core.exceptions import ValidationError from django.db.utils import IntegrityError -from build.models import Build, BuildItem +from InvenTree import status_codes as status + +from build.models import Build, BuildItem, get_next_build_number from stock.models import StockItem from part.models import Part, BomItem -from InvenTree import status_codes as status class BuildTest(TestCase): @@ -80,8 +81,14 @@ class BuildTest(TestCase): quantity=2 ) + ref = get_next_build_number() + + if ref is None: + ref = "0001" + # Create a "Build" object to make 10x objects self.build = Build.objects.create( + reference=ref, title="This is a build", part=self.assembly, quantity=10 diff --git a/InvenTree/build/tests.py b/InvenTree/build/tests.py index 9a440e0b93..b5e5406f69 100644 --- a/InvenTree/build/tests.py +++ b/InvenTree/build/tests.py @@ -252,36 +252,6 @@ class TestBuildViews(TestCase): self.assertIn(build.title, content) - def test_build_create(self): - """ Test the build creation view (ajax form) """ - - url = reverse('build-create') - - # Create build without specifying part - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Create build with valid part - response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Create build with invalid part - response = self.client.get(url, {'part': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - def test_build_allocate(self): - """ Test the part allocation view for a Build """ - - url = reverse('build-allocate', args=(1,)) - - # Get the page normally - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - - # Get the page in editing mode - response = self.client.get(url, {'edit': 1}) - self.assertEqual(response.status_code, 200) - def test_build_item_create(self): """ Test the BuildItem creation view (ajax form) """ diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index 99b6b72818..9814dc83f7 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -7,43 +7,27 @@ from django.conf.urls import url, include from . import views build_detail_urls = [ - url(r'^edit/', views.BuildUpdate.as_view(), name='build-edit'), - url(r'^allocate/', views.BuildAllocate.as_view(), name='build-allocate'), url(r'^cancel/', views.BuildCancel.as_view(), name='build-cancel'), url(r'^delete/', views.BuildDelete.as_view(), name='build-delete'), url(r'^create-output/', views.BuildOutputCreate.as_view(), name='build-output-create'), url(r'^delete-output/', views.BuildOutputDelete.as_view(), name='build-output-delete'), - url(r'^complete-output/?', views.BuildOutputComplete.as_view(), name='build-output-complete'), - url(r'^auto-allocate/?', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), + url(r'^complete-output/', views.BuildOutputComplete.as_view(), name='build-output-complete'), + url(r'^auto-allocate/', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), url(r'^unallocate/', views.BuildUnallocate.as_view(), name='build-unallocate'), url(r'^complete/', views.BuildComplete.as_view(), name='build-complete'), - url(r'^notes/', views.BuildNotes.as_view(), name='build-notes'), - - url(r'^children/', views.BuildDetail.as_view(template_name='build/build_children.html'), name='build-children'), - url(r'^attachments/', views.BuildDetail.as_view(template_name='build/attachments.html'), name='build-attachments'), - url(r'^output/', views.BuildDetail.as_view(template_name='build/build_output.html'), name='build-output'), - url(r'^.*$', views.BuildDetail.as_view(), name='build-detail'), ] build_urls = [ url(r'item/', include([ url(r'^(?P\d+)/', include([ - url('^edit/?', views.BuildItemEdit.as_view(), name='build-item-edit'), - url('^delete/?', views.BuildItemDelete.as_view(), name='build-item-delete'), + url('^edit/', views.BuildItemEdit.as_view(), name='build-item-edit'), + url('^delete/', views.BuildItemDelete.as_view(), name='build-item-delete'), ])), url('^new/', views.BuildItemCreate.as_view(), name='build-item-create'), ])), - url('^attachment/', include([ - url('^new/', views.BuildAttachmentCreate.as_view(), name='build-attachment-create'), - url(r'^(?P\d+)/edit/', views.BuildAttachmentEdit.as_view(), name='build-attachment-edit'), - url(r'^(?P\d+)/delete/', views.BuildAttachmentDelete.as_view(), name='build-attachment-delete'), - ])), - - url(r'new/', views.BuildCreate.as_view(), name='build-create'), - url(r'^(?P\d+)/', include(build_detail_urls)), url(r'.*$', views.BuildIndex.as_view(), name='build-index'), diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 6e72f7f3e6..dfa655f9a4 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -7,12 +7,11 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ValidationError -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.forms import HiddenInput -from django.urls import reverse from part.models import Part -from .models import Build, BuildItem, BuildOrderAttachment +from .models import Build, BuildItem from . import forms from stock.models import StockLocation, StockItem @@ -593,31 +592,6 @@ class BuildOutputComplete(AjaxUpdateView): } -class BuildNotes(InvenTreeRoleMixin, UpdateView): - """ View for editing the 'notes' field of a Build object. - """ - - context_object_name = 'build' - template_name = 'build/notes.html' - model = Build - - # Override the default permission role for this View - role_required = 'build.view' - - fields = ['notes'] - - def get_success_url(self): - return reverse('build-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', '')) - - return ctx - - class BuildDetail(InvenTreeRoleMixin, DetailView): """ Detail view of a single Build object. """ @@ -635,156 +609,15 @@ class BuildDetail(InvenTreeRoleMixin, DetailView): ctx['BuildStatus'] = BuildStatus ctx['sub_build_count'] = build.sub_build_count() - return ctx - - -class BuildAllocate(InvenTreeRoleMixin, DetailView): - """ View for allocating parts to a Build """ - model = Build - context_object_name = 'build' - template_name = 'build/allocate.html' - - def get_context_data(self, **kwargs): - """ Provide extra context information for the Build allocation page """ - - context = super(DetailView, self).get_context_data(**kwargs) - - build = self.get_object() part = build.part bom_items = build.bom_items - context['part'] = part - context['bom_items'] = bom_items - context['has_tracked_bom_items'] = build.has_tracked_bom_items() - context['has_untracked_bom_items'] = build.has_untracked_bom_items() - context['BuildStatus'] = BuildStatus + ctx['part'] = part + ctx['bom_items'] = bom_items + ctx['has_tracked_bom_items'] = build.has_tracked_bom_items() + ctx['has_untracked_bom_items'] = build.has_untracked_bom_items() - context['bom_price'] = build.part.get_price_info(build.quantity, buy=False) - - if str2bool(self.request.GET.get('edit', None)): - context['editing'] = True - - return context - - -class BuildCreate(AjaxCreateView): - """ - View to create a new Build object - """ - - model = Build - context_object_name = 'build' - form_class = forms.EditBuildForm - ajax_form_title = _('New Build Order') - ajax_template_name = 'modal_form.html' - - def get_form(self): - form = super().get_form() - - if form['part'].value(): - form.fields['part'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Get initial parameters for Build creation. - - If 'part' is specified in the GET query, initialize the Build with the specified Part - """ - - initials = super(BuildCreate, self).get_initial().copy() - - initials['parent'] = self.request.GET.get('parent', None) - - # User has provided a SalesOrder ID - initials['sales_order'] = self.request.GET.get('sales_order', None) - - initials['quantity'] = self.request.GET.get('quantity', 1) - - part = self.request.GET.get('part', None) - - if part: - - try: - part = Part.objects.get(pk=part) - # User has provided a Part ID - initials['part'] = part - initials['destination'] = part.get_default_location() - - to_order = part.quantity_to_order - - if to_order < 1: - to_order = 1 - - initials['quantity'] = to_order - except (ValueError, Part.DoesNotExist): - pass - - initials['reference'] = Build.getNextBuildNumber() - - # Pre-fill the issued_by user - initials['issued_by'] = self.request.user - - return initials - - def get_data(self): - return { - 'success': _('Created new build'), - } - - def validate(self, build, form, **kwargs): - """ - Perform extra form validation. - - - If part is trackable, check that either batch or serial numbers are calculated - - By this point form.is_valid() has been executed - """ - - pass - - -class BuildUpdate(AjaxUpdateView): - """ View for editing a Build object """ - - model = Build - form_class = forms.EditBuildForm - context_object_name = 'build' - ajax_form_title = _('Edit Build Order Details') - ajax_template_name = 'modal_form.html' - - def get_form(self): - - form = super().get_form() - - build = self.get_object() - - # Fields which are included in the form, but hidden - hidden = [ - 'parent', - 'sales_order', - ] - - if build.is_complete: - # Fields which cannot be edited once the build has been completed - - hidden += [ - 'part', - 'quantity', - 'batch', - 'take_from', - 'destination', - ] - - for field in hidden: - form.fields[field].widget = HiddenInput() - - return form - - def get_data(self): - return { - 'info': _('Edited build'), - } + return ctx class BuildDelete(AjaxDeleteView): @@ -1058,88 +891,3 @@ class BuildItemEdit(AjaxUpdateView): form.fields['install_into'].widget = HiddenInput() return form - - -class BuildAttachmentCreate(AjaxCreateView): - """ - View for creating a BuildAttachment - """ - - model = BuildOrderAttachment - form_class = forms.EditBuildAttachmentForm - ajax_form_title = _('Add Build Order Attachment') - - def save(self, form, **kwargs): - """ - Add information on the user that uploaded the attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - """ - Get initial data for creating an attachment - """ - - initials = super().get_initial() - - try: - initials['build'] = Build.objects.get(pk=self.request.GET.get('build', -1)) - except (ValueError, Build.DoesNotExist): - pass - - return initials - - def get_form(self): - """ - Hide the 'build' field if specified - """ - - form = super().get_form() - - form.fields['build'].widget = HiddenInput() - - return form - - -class BuildAttachmentEdit(AjaxUpdateView): - """ - View for editing a BuildAttachment object - """ - - model = BuildOrderAttachment - form_class = forms.EditBuildAttachmentForm - ajax_form_title = _('Edit Attachment') - - def get_form(self): - form = super().get_form() - form.fields['build'].widget = HiddenInput() - - return form - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - -class BuildAttachmentDelete(AjaxDeleteView): - """ - View for deleting a BuildAttachment - """ - - model = BuildOrderAttachment - ajax_form_title = _('Delete Attachment') - context_object_name = 'attachment' - - def get_data(self): - return { - 'danger': _('Deleted attachment') - } diff --git a/InvenTree/common/files.py b/InvenTree/common/files.py index 377120f44d..45b6c80050 100644 --- a/InvenTree/common/files.py +++ b/InvenTree/common/files.py @@ -22,17 +22,19 @@ class FileManager: # Fields which are used for item matching (only one of them is needed) ITEM_MATCH_HEADERS = [] - + # Fields which would be helpful but are not required OPTIONAL_HEADERS = [] + OPTIONAL_MATCH_HEADERS = [] + EDITABLE_HEADERS = [] HEADERS = [] def __init__(self, file, name=None): """ Initialize the FileManager class with a user-uploaded file object """ - + # Set name if name: self.name = name @@ -71,52 +73,44 @@ class FileManager: raise ValidationError(_('Error reading file (incorrect dimension)')) except KeyError: raise ValidationError(_('Error reading file (data could be corrupted)')) - + return cleaned_data def process(self, file): """ Process file """ self.data = self.__class__.validate(file) - + def update_headers(self): """ Update headers """ - self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_HEADERS - + self.HEADERS = self.REQUIRED_HEADERS + self.ITEM_MATCH_HEADERS + self.OPTIONAL_MATCH_HEADERS + self.OPTIONAL_HEADERS + def setup(self): - """ Setup headers depending on the file name """ + """ + Setup headers + should be overriden in usage to set the Different Headers + """ if not self.name: return - if self.name == 'order': - self.REQUIRED_HEADERS = [ - 'Quantity', - ] - - self.ITEM_MATCH_HEADERS = [ - 'Manufacturer_MPN', - 'Supplier_SKU', - ] - - self.OPTIONAL_HEADERS = [ - 'Purchase_Price', - 'Reference', - 'Notes', - ] - - # Update headers - self.update_headers() + # Update headers + self.update_headers() def guess_header(self, header, threshold=80): - """ Try to match a header (from the file) to a list of known headers - + """ + Try to match a header (from the file) to a list of known headers + Args: header - Header name to look for threshold - Match threshold for fuzzy search """ + # Replace null values with empty string + if header is None: + header = '' + # Try for an exact match for h in self.HEADERS: if h == header: @@ -145,7 +139,7 @@ class FileManager: return matches[0]['header'] return None - + def columns(self): """ Return a list of headers for the thingy """ headers = [] diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index f161c8cc01..4a2a1601aa 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -8,12 +8,7 @@ from __future__ import unicode_literals from django import forms from django.utils.translation import gettext as _ -from djmoney.forms.fields import MoneyField - from InvenTree.forms import HelperForm -from InvenTree.helpers import clean_decimal - -from common.settings import currency_code_default from .files import FileManager from .models import InvenTreeSetting @@ -32,7 +27,7 @@ class SettingEditForm(HelperForm): ] -class UploadFile(forms.Form): +class UploadFileForm(forms.Form): """ Step 1 of FileManagementFormView """ file = forms.FileField( @@ -70,9 +65,9 @@ class UploadFile(forms.Form): return file -class MatchField(forms.Form): +class MatchFieldForm(forms.Form): """ Step 2 of FileManagementFormView """ - + def __init__(self, *args, **kwargs): # Get FileManager @@ -88,7 +83,7 @@ class MatchField(forms.Form): columns = file_manager.columns() # Get headers choices headers_choices = [(header, header) for header in file_manager.HEADERS] - + # Create column fields for col in columns: field_name = col['name'] @@ -103,9 +98,9 @@ class MatchField(forms.Form): self.fields[field_name].initial = col['guess'] -class MatchItem(forms.Form): +class MatchItemForm(forms.Form): """ Step 3 of FileManagementFormView """ - + def __init__(self, *args, **kwargs): # Get FileManager @@ -131,24 +126,41 @@ class MatchItem(forms.Form): for col in row['data']: # Get column matching col_guess = col['column'].get('guess', None) + # Set field name + field_name = col_guess.lower() + '-' + str(row['index']) + + # check if field def was overriden + overriden_field = self.get_special_field(col_guess, row, file_manager) + if overriden_field: + self.fields[field_name] = overriden_field # Create input for required headers - if col_guess in file_manager.REQUIRED_HEADERS: - # Set field name - field_name = col_guess.lower() + '-' + str(row['index']) + elif col_guess in file_manager.REQUIRED_HEADERS: + # Get value + value = row.get(col_guess.lower(), '') # Set field input box - if 'quantity' in col_guess.lower(): - self.fields[field_name] = forms.CharField( - required=False, - widget=forms.NumberInput(attrs={ - 'name': 'quantity' + str(row['index']), - 'class': 'numberinput', # form-control', - 'type': 'number', - 'min': '0', - 'step': 'any', - 'value': clean_decimal(row.get('quantity', '')), - }) - ) + self.fields[field_name] = forms.CharField( + required=True, + initial=value, + ) + + # Create item selection box + elif col_guess in file_manager.OPTIONAL_MATCH_HEADERS: + # Get item options + item_options = [(option.id, option) for option in row['match_options_' + col_guess]] + # Get item match + item_match = row['match_' + col_guess] + # Set field select box + self.fields[field_name] = forms.ChoiceField( + choices=[('', '-' * 10)] + item_options, + required=False, + widget=forms.Select(attrs={ + 'class': 'select bomselect', + }) + ) + # Update select box when match was found + if item_match: + self.fields[field_name].initial = item_match.id # Create item selection box elif col_guess in file_manager.ITEM_MATCH_HEADERS: @@ -176,22 +188,15 @@ class MatchItem(forms.Form): # Optional entries elif col_guess in file_manager.OPTIONAL_HEADERS: - # Set field name - field_name = col_guess.lower() + '-' + str(row['index']) # Get value value = row.get(col_guess.lower(), '') # Set field input box - if 'price' in col_guess.lower(): - self.fields[field_name] = MoneyField( - label=_(col_guess), - default_currency=currency_code_default(), - decimal_places=5, - max_digits=19, - required=False, - default_amount=clean_decimal(value), - ) - else: - self.fields[field_name] = forms.CharField( - required=False, - initial=value, - ) + self.fields[field_name] = forms.CharField( + required=False, + initial=value, + ) + + def get_special_field(self, col_guess, row, file_manager): + """ Function to be overriden in inherited forms to add specific form settings """ + + return None diff --git a/InvenTree/common/migrations/0010_migrate_currency_setting.py b/InvenTree/common/migrations/0010_migrate_currency_setting.py new file mode 100644 index 0000000000..23076ff200 --- /dev/null +++ b/InvenTree/common/migrations/0010_migrate_currency_setting.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.4 on 2021-07-01 15:39 + +from django.db import migrations +from common.models import InvenTreeSetting +from InvenTree.settings import get_setting, CONFIG + +def set_default_currency(apps, schema_editor): + """ migrate the currency setting from config.yml to db """ + # get value from settings-file + base_currency = get_setting('INVENTREE_BASE_CURRENCY', CONFIG.get('base_currency', 'USD')) + # write to database + InvenTreeSetting.set_setting('INVENTREE_DEFAULT_CURRENCY', base_currency, None, create=True) + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0009_delete_currency'), + ] + + operations = [ + migrations.RunPython(set_default_currency), + ] diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index b78fe1c2bf..3d18d56880 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -14,11 +14,11 @@ from django.db import models, transaction from django.db.utils import IntegrityError, OperationalError from django.conf import settings -from djmoney.models.fields import MoneyField +from djmoney.settings import CURRENCY_CHOICES from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate -from common.settings import currency_code_default +import common.settings from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator, URLValidator @@ -81,6 +81,13 @@ class InvenTreeSetting(models.Model): 'default': '', }, + 'INVENTREE_DEFAULT_CURRENCY': { + 'name': _('Default Currency'), + 'description': _('Default currency'), + 'default': 'USD', + 'choices': CURRENCY_CHOICES, + }, + 'INVENTREE_DOWNLOAD_FROM_URL': { 'name': _('Download from URL'), 'description': _('Allow download of remote images and files from external URL'), @@ -205,6 +212,13 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_SHOW_IMPORT': { + 'name': _('Show Import in Views'), + 'description': _('Display the import wizard in some part views'), + 'default': False, + 'validator': bool, + }, + 'PART_SHOW_PRICE_IN_FORMS': { 'name': _('Show Price in Forms'), 'description': _('Display part price in some forms'), @@ -212,6 +226,20 @@ class InvenTreeSetting(models.Model): 'validator': bool, }, + 'PART_SHOW_RELATED': { + 'name': _('Show related parts'), + 'description': _('Display related parts for a part'), + 'default': True, + 'validator': bool, + }, + + 'PART_CREATE_INITIAL': { + 'name': _('Create initial stock'), + 'description': _('Create initial stock on part creation'), + 'default': False, + 'validator': bool, + }, + 'PART_INTERNAL_PRICE': { 'name': _('Internal Prices'), 'description': _('Enable internal prices for parts'), @@ -721,10 +749,9 @@ class PriceBreak(models.Model): help_text=_('Price break quantity'), ) - price = MoneyField( + price = InvenTree.fields.InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), null=True, verbose_name=_('Price'), help_text=_('Unit price at specified quantity'), @@ -777,7 +804,7 @@ def get_price(instance, quantity, moq=True, multiples=True, currency=None, break if currency is None: # Default currency selection - currency = currency_code_default() + currency = common.settings.currency_code_default() pb_min = None for pb in price_breaks: diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 60265f4cb9..b34cf0b785 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -6,9 +6,9 @@ User-configurable settings for the common app from __future__ import unicode_literals from moneyed import CURRENCIES +from django.conf import settings import common.models -from django.conf import settings def currency_code_default(): @@ -16,7 +16,7 @@ def currency_code_default(): Returns the default currency code (or USD if not specified) """ - code = settings.BASE_CURRENCY + code = common.models.InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') if code not in CURRENCIES: code = 'USD' @@ -24,6 +24,20 @@ def currency_code_default(): return code +def currency_code_mappings(): + """ + Returns the current currency choices + """ + return [(a, CURRENCIES[a].name) for a in settings.CURRENCIES] + + +def currency_codes(): + """ + Returns the current currency codes + """ + return [a for a in settings.CURRENCIES] + + def stock_expiry_enabled(): """ Returns True if the stock expiry feature is enabled diff --git a/InvenTree/common/views.py b/InvenTree/common/views.py index 857b6b2c51..f953dffa81 100644 --- a/InvenTree/common/views.py +++ b/InvenTree/common/views.py @@ -13,8 +13,9 @@ from django.conf import settings from django.core.files.storage import FileSystemStorage from formtools.wizard.views import SessionWizardView +from crispy_forms.helper import FormHelper -from InvenTree.views import AjaxUpdateView +from InvenTree.views import AjaxUpdateView, AjaxView from InvenTree.helpers import str2bool from . import models @@ -117,7 +118,6 @@ class MultiStepFormView(SessionWizardView): form_steps_description: description for each form """ - form_list = [] form_steps_template = [] form_steps_description = [] file_manager = None @@ -126,10 +126,10 @@ class MultiStepFormView(SessionWizardView): def __init__(self, *args, **kwargs): """ Override init method to set media folder """ - super().__init__(*args, **kwargs) + super().__init__(**kwargs) self.process_media_folder() - + def process_media_folder(self): """ Process media folder """ @@ -141,7 +141,7 @@ class MultiStepFormView(SessionWizardView): def get_template_names(self): """ Select template """ - + try: # Get template template = self.form_steps_template[self.steps.index] @@ -152,7 +152,7 @@ class MultiStepFormView(SessionWizardView): def get_context_data(self, **kwargs): """ Update context data """ - + # Retrieve current context context = super().get_context_data(**kwargs) @@ -176,9 +176,9 @@ class FileManagementFormView(MultiStepFormView): name = None form_list = [ - ('upload', forms.UploadFile), - ('fields', forms.MatchField), - ('items', forms.MatchItem), + ('upload', forms.UploadFileForm), + ('fields', forms.MatchFieldForm), + ('items', forms.MatchItemForm), ] form_steps_description = [ _("Upload File"), @@ -188,11 +188,26 @@ class FileManagementFormView(MultiStepFormView): media_folder = 'file_upload/' extra_context_data = {} - def get_context_data(self, form, **kwargs): + def __init__(self, *args, **kwargs): + """ Initialize the FormView """ + + # Perform all checks and inits for MultiStepFormView + super().__init__(self, *args, **kwargs) + + # Check for file manager class + if not hasattr(self, 'file_manager_class') and not issubclass(self.file_manager_class, FileManager): + raise NotImplementedError('A subclass of a file manager class needs to be set!') + + def get_context_data(self, form=None, **kwargs): + """ Handle context data """ + + if form is None: + form = self.get_form() + context = super().get_context_data(form=form, **kwargs) if self.steps.current in ('fields', 'items'): - + # Get columns and row data self.columns = self.file_manager.columns() self.rows = self.file_manager.rows() @@ -203,7 +218,7 @@ class FileManagementFormView(MultiStepFormView): elif self.steps.current == 'items': # Set form table data self.set_form_table_data(form=form) - + # Update context context.update({'rows': self.rows}) context.update({'columns': self.columns}) @@ -227,7 +242,7 @@ class FileManagementFormView(MultiStepFormView): # Get file file = upload_files.get('upload-file', None) if file: - self.file_manager = FileManager(file=file, name=self.name) + self.file_manager = self.file_manager_class(file=file, name=self.name) def get_form_kwargs(self, step=None): """ Update kwargs to dynamically build forms """ @@ -262,13 +277,22 @@ class FileManagementFormView(MultiStepFormView): self.get_form_table_data(data) self.set_form_table_data() self.get_field_selection() - + kwargs['row_data'] = self.rows return kwargs - + return super().get_form_kwargs() + def get_form(self, step=None, data=None, files=None): + """ add crispy-form helper to form """ + form = super().get_form(step=step, data=data, files=files) + + form.helper = FormHelper() + form.helper.form_show_labels = False + + return form + def get_form_table_data(self, form_data): """ Extract table cell data from form data and fields. These data are used to maintain state between sessions. @@ -327,7 +351,7 @@ class FileManagementFormView(MultiStepFormView): col_id = int(s[3]) except ValueError: continue - + if row_id not in self.row_data: self.row_data[row_id] = {} @@ -362,19 +386,20 @@ class FileManagementFormView(MultiStepFormView): 'name': self.column_names[idx], 'guess': self.column_selections[idx], } - + cell_data = { 'cell': item, 'idx': idx, 'column': column_data, } data.append(cell_data) - + row = { 'index': row_idx, 'data': data, 'errors': {}, } + self.rows.append(row) # In the item selection step: update row data with mapping to form fields @@ -414,6 +439,33 @@ class FileManagementFormView(MultiStepFormView): """ pass + def get_clean_items(self): + """ returns dict with all cleaned values """ + items = {} + + for form_key, form_value in self.get_all_cleaned_data().items(): + # Split key from row value + try: + (field, idx) = form_key.split('-') + except ValueError: + continue + + try: + if idx not in items: + # Insert into items + items.update({ + idx: { + self.form_field_map[field]: form_value, + } + }) + else: + # Update items + items[idx][self.form_field_map[field]] = form_value + except KeyError: + pass + + return items + def check_field_selection(self, form): """ Check field matching """ @@ -431,7 +483,7 @@ class FileManagementFormView(MultiStepFormView): if col in self.column_selections.values(): part_match_found = True break - + # If not, notify user if not part_match_found: for col in self.file_manager.ITEM_MATCH_HEADERS: @@ -451,7 +503,7 @@ class FileManagementFormView(MultiStepFormView): n = list(self.column_selections.values()).count(self.column_selections[col]) if n > 1 and self.column_selections[col] not in duplicates: duplicates.append(self.column_selections[col]) - + # Store extra context data self.extra_context_data = { 'missing_columns': missing_columns, @@ -497,3 +549,70 @@ class FileManagementFormView(MultiStepFormView): return self.render(form) return super().post(*args, **kwargs) + + +class FileManagementAjaxView(AjaxView): + """ Use a FileManagementFormView as base for a AjaxView + Inherit this class before inheriting the base FileManagementFormView + + ajax_form_steps_template: templates for rendering ajax + validate: function to validate the current form -> normally point to the same function in the base FileManagementFormView + """ + + def post(self, request): + # check if back-step button was selected + wizard_back = self.request.POST.get('act-btn_back', None) + if wizard_back: + back_step_index = self.get_step_index() - 1 + self.storage.current_step = list(self.get_form_list().keys())[back_step_index] + return self.renderJsonResponse(request, data={'form_valid': None}) + + # validate form + form = self.get_form(data=self.request.POST, files=self.request.FILES) + form_valid = self.validate(self.steps.current, form) + + # check if valid + if not form_valid: + return self.renderJsonResponse(request, data={'form_valid': None}) + + # store the cleaned data and files. + self.storage.set_step_data(self.steps.current, self.process_step(form)) + self.storage.set_step_files(self.steps.current, self.process_step_files(form)) + + # check if the current step is the last step + if self.steps.current == self.steps.last: + # call done - to process data, returned response is not used + self.render_done(form) + data = {'form_valid': True, 'success': _('Parts imported')} + return self.renderJsonResponse(request, data=data) + else: + self.storage.current_step = self.steps.next + + return self.renderJsonResponse(request, data={'form_valid': None}) + + def get(self, request): + if 'reset' in request.GET: + # reset form + self.storage.reset() + self.storage.current_step = self.steps.first + return self.renderJsonResponse(request) + + def renderJsonResponse(self, request, form=None, data={}, context=None): + """ always set the right templates before rendering """ + self.setTemplate() + return super().renderJsonResponse(request, form=form, data=data, context=context) + + def get_data(self): + data = super().get_data() + data['hideErrorMessage'] = '1' # hide the error + buttons = [{'name': 'back', 'title': _('Previous Step')}] if self.get_step_index() > 0 else [] + data['buttons'] = buttons # set buttons + return data + + def setTemplate(self): + """ set template name and title """ + self.ajax_template_name = self.ajax_form_steps_template[self.get_step_index()] + self.ajax_form_title = self.form_steps_description[self.get_step_index()] + + def validate(self, obj, form, **kwargs): + raise NotImplementedError('This function needs to be overridden!') diff --git a/InvenTree/company/api.py b/InvenTree/company/api.py index 6cd1e83dfa..76b08ec27e 100644 --- a/InvenTree/company/api.py +++ b/InvenTree/company/api.py @@ -158,6 +158,7 @@ class ManufacturerPartList(generics.ListCreateAPIView): 'manufacturer__name', 'description', 'MPN', + 'part__IPN', 'part__name', 'part__description', ] @@ -262,11 +263,7 @@ class SupplierPartList(generics.ListCreateAPIView): - POST: Create a new SupplierPart object """ - queryset = SupplierPart.objects.all().prefetch_related( - 'part', - 'supplier', - 'manufacturer_part__manufacturer', - ) + queryset = SupplierPart.objects.all() def get_queryset(self): @@ -355,6 +352,7 @@ class SupplierPartList(generics.ListCreateAPIView): 'manufacturer_part__manufacturer__name', 'description', 'manufacturer_part__MPN', + 'part__IPN', 'part__name', 'part__description', ] @@ -394,6 +392,15 @@ class SupplierPriceBreakList(generics.ListCreateAPIView): ] +class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for SupplierPriceBreak object + """ + + queryset = SupplierPriceBreak.objects.all() + serializer_class = SupplierPriceBreakSerializer + + manufacturer_part_api_urls = [ url(r'^parameter/', include([ @@ -424,7 +431,12 @@ company_api_urls = [ url(r'^part/', include(supplier_part_api_urls)), - url(r'^price-break/', SupplierPriceBreakList.as_view(), name='api-part-supplier-price'), + # Supplier price breaks + url(r'^price-break/', include([ + + url(r'^(?P\d+)/?', SupplierPriceBreakDetail.as_view(), name='api-part-supplier-price-detail'), + url(r'^.*$', SupplierPriceBreakList.as_view(), name='api-part-supplier-price-list'), + ])), url(r'^(?P\d+)/?', CompanyDetail.as_view(), name='api-company-detail'), diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 80673b4fa4..506133df00 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -11,63 +11,10 @@ from InvenTree.fields import RoundingDecimalFormField from django.utils.translation import ugettext_lazy as _ import django.forms -import djmoney.settings -from djmoney.forms.fields import MoneyField - -from common.settings import currency_code_default - -from .models import Company, ManufacturerPartParameter -from .models import ManufacturerPart -from .models import SupplierPart +from .models import Company from .models import SupplierPriceBreak -class EditCompanyForm(HelperForm): - """ Form for editing a Company object """ - - field_prefix = { - 'website': 'fa-globe-asia', - 'email': 'fa-at', - 'address': 'fa-envelope', - 'contact': 'fa-user-tie', - 'phone': 'fa-phone', - } - - currency = django.forms.ChoiceField( - required=False, - label=_('Currency'), - help_text=_('Default currency used for this company'), - choices=[('', '----------')] + djmoney.settings.CURRENCY_CHOICES, - initial=currency_code_default, - ) - - class Meta: - model = Company - fields = [ - 'name', - 'description', - 'website', - 'address', - 'currency', - 'phone', - 'email', - 'contact', - 'is_supplier', - 'is_manufacturer', - 'is_customer', - ] - - -class CompanyImageForm(HelperForm): - """ Form for uploading a Company image """ - - class Meta: - model = Company - fields = [ - 'image' - ] - - class CompanyImageDownloadForm(HelperForm): """ Form for downloading an image from a URL @@ -86,102 +33,6 @@ class CompanyImageDownloadForm(HelperForm): ] -class EditManufacturerPartForm(HelperForm): - """ Form for editing a ManufacturerPart object """ - - field_prefix = { - 'link': 'fa-link', - 'MPN': 'fa-hashtag', - } - - class Meta: - model = ManufacturerPart - fields = [ - 'part', - 'manufacturer', - 'MPN', - 'description', - 'link', - ] - - -class EditManufacturerPartParameterForm(HelperForm): - """ - Form for creating / editing a ManufacturerPartParameter object - """ - - class Meta: - model = ManufacturerPartParameter - fields = [ - 'manufacturer_part', - 'name', - 'value', - 'units', - ] - - -class EditSupplierPartForm(HelperForm): - """ Form for editing a SupplierPart object """ - - field_prefix = { - 'link': 'fa-link', - 'SKU': 'fa-hashtag', - 'note': 'fa-pencil-alt', - } - - single_pricing = MoneyField( - label=_('Single Price'), - default_currency=currency_code_default(), - help_text=_('Single quantity price'), - decimal_places=4, - max_digits=19, - required=False, - ) - - manufacturer = django.forms.ChoiceField( - required=False, - help_text=_('Select manufacturer'), - choices=[], - ) - - MPN = django.forms.CharField( - required=False, - help_text=_('Manufacturer Part Number'), - max_length=100, - label=_('MPN'), - ) - - class Meta: - model = SupplierPart - fields = [ - 'part', - 'supplier', - 'SKU', - 'manufacturer', - 'MPN', - 'description', - 'link', - 'note', - 'single_pricing', - # 'base_cost', - # 'multiple', - 'packaging', - ] - - def get_manufacturer_choices(self): - """ Returns tuples for all manufacturers """ - empty_choice = [('', '----------')] - - manufacturers = [(manufacturer.id, manufacturer.name) for manufacturer in Company.objects.filter(is_manufacturer=True)] - - return empty_choice + manufacturers - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fields['manufacturer'].choices = self.get_manufacturer_choices() - - class EditPriceBreakForm(HelperForm): """ Form for creating / editing a supplier price break """ diff --git a/InvenTree/company/migrations/0026_auto_20201110_1011.py b/InvenTree/company/migrations/0026_auto_20201110_1011.py index 20ec7d2f6f..29a5099c3a 100644 --- a/InvenTree/company/migrations/0026_auto_20201110_1011.py +++ b/InvenTree/company/migrations/0026_auto_20201110_1011.py @@ -1,5 +1,6 @@ # Generated by Django 3.0.7 on 2020-11-10 10:11 +import logging import sys from moneyed import CURRENCIES @@ -7,6 +8,9 @@ from django.db import migrations, connection from company.models import SupplierPriceBreak +logger = logging.getLogger('inventree') + + def migrate_currencies(apps, schema_editor): """ Migrate from the 'old' method of handling currencies, @@ -19,7 +23,7 @@ def migrate_currencies(apps, schema_editor): for the SupplierPriceBreak model, to a new django-money compatible currency. """ - print("Updating currency references for SupplierPriceBreak model...") + logger.info("Updating currency references for SupplierPriceBreak model...") # A list of available currency codes currency_codes = CURRENCIES.keys() @@ -39,7 +43,7 @@ def migrate_currencies(apps, schema_editor): suffix = suffix.strip().upper() if suffix not in currency_codes: - print("Missing suffix:", suffix) + logger.warning(f"Missing suffix: '{suffix}'") while suffix not in currency_codes: # Ask the user to input a valid currency @@ -72,7 +76,7 @@ def migrate_currencies(apps, schema_editor): count += 1 if count > 0: - print(f"Updated {count} SupplierPriceBreak rows") + logger.info(f"Updated {count} SupplierPriceBreak rows") def reverse_currencies(apps, schema_editor): """ diff --git a/InvenTree/company/migrations/0039_auto_20210701_0509.py b/InvenTree/company/migrations/0039_auto_20210701_0509.py new file mode 100644 index 0000000000..094c7a5009 --- /dev/null +++ b/InvenTree/company/migrations/0039_auto_20210701_0509.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0038_manufacturerpartparameter'), + ] + + operations = [ + migrations.AlterField( + model_name='supplierpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='supplierpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/company/migrations/0040_alter_company_currency.py b/InvenTree/company/migrations/0040_alter_company_currency.py new file mode 100644 index 0000000000..f26f470191 --- /dev/null +++ b/InvenTree/company/migrations/0040_alter_company_currency.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.4 on 2021-07-02 13:21 + +import InvenTree.validators +import common.settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0039_auto_20210701_0509'), + ] + + operations = [ + migrations.AlterField( + model_name='company', + name='currency', + field=models.CharField(blank=True, default=common.settings.currency_code_default, help_text='Default currency used for this company', max_length=3, validators=[InvenTree.validators.validate_currency_code], verbose_name='Currency'), + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index 093d545f78..3b731381b8 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -9,9 +9,7 @@ import os from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator -from django.core.exceptions import ValidationError from django.db import models -from django.db.utils import IntegrityError from django.db.models import Sum, Q, UniqueConstraint from django.apps import apps @@ -31,6 +29,7 @@ import InvenTree.validators import common.models import common.settings +from common.settings import currency_code_default def rename_company_image(instance, filename): @@ -84,6 +83,10 @@ class Company(models.Model): currency_code: Specifies the default currency for the company """ + @staticmethod + def get_api_url(): + return reverse('api-company-list') + class Meta: ordering = ['name', ] constraints = [ @@ -101,7 +104,11 @@ class Company(models.Model): blank=True, ) - website = models.URLField(blank=True, verbose_name=_('Website'), help_text=_('Company website URL')) + website = models.URLField( + blank=True, + verbose_name=_('Website'), + help_text=_('Company website URL') + ) address = models.CharField(max_length=200, verbose_name=_('Address'), @@ -141,6 +148,7 @@ class Company(models.Model): max_length=3, verbose_name=_('Currency'), blank=True, + default=currency_code_default, help_text=_('Default currency used for this company'), validators=[InvenTree.validators.validate_currency_code], ) @@ -297,6 +305,10 @@ class ManufacturerPart(models.Model): description: Descriptive notes field """ + @staticmethod + def get_api_url(): + return reverse('api-manufacturer-part-list') + class Meta: unique_together = ('part', 'manufacturer', 'MPN') @@ -380,6 +392,10 @@ class ManufacturerPartParameter(models.Model): Each parameter is a simple string (text) value. """ + @staticmethod + def get_api_url(): + return reverse('api-manufacturer-part-parameter-list') + class Meta: unique_together = ('manufacturer_part', 'name') @@ -412,6 +428,22 @@ class ManufacturerPartParameter(models.Model): ) +class SupplierPartManager(models.Manager): + """ Define custom SupplierPart objects manager + + The main purpose of this manager is to improve database hit as the + SupplierPart model involves A LOT of foreign keys lookups + """ + + def get_queryset(self): + # Always prefetch related models + return super().get_queryset().prefetch_related( + 'part', + 'supplier', + 'manufacturer_part__manufacturer', + ) + + class SupplierPart(models.Model): """ Represents a unique part as provided by a Supplier Each SupplierPart is identified by a SKU (Supplier Part Number) @@ -432,60 +464,15 @@ class SupplierPart(models.Model): packaging: packaging that the part is supplied in, e.g. "Reel" """ + objects = SupplierPartManager() + + @staticmethod + def get_api_url(): + return reverse('api-supplier-part-list') + def get_absolute_url(self): return reverse('supplier-part-detail', kwargs={'pk': self.id}) - def save(self, *args, **kwargs): - """ Overriding save method to process the linked ManufacturerPart - """ - - if 'manufacturer' in kwargs: - manufacturer_id = kwargs.pop('manufacturer') - - try: - manufacturer = Company.objects.get(pk=int(manufacturer_id)) - except (ValueError, Company.DoesNotExist): - manufacturer = None - else: - manufacturer = None - if 'MPN' in kwargs: - MPN = kwargs.pop('MPN') - else: - MPN = None - - if manufacturer or MPN: - if not self.manufacturer_part: - # Create ManufacturerPart - manufacturer_part = ManufacturerPart.create(part=self.part, - manufacturer=manufacturer, - mpn=MPN, - description=self.description) - self.manufacturer_part = manufacturer_part - else: - # Update ManufacturerPart (if ID exists) - try: - manufacturer_part_id = self.manufacturer_part.id - except AttributeError: - manufacturer_part_id = None - - if manufacturer_part_id: - try: - (manufacturer_part, created) = ManufacturerPart.objects.update_or_create(part=self.part, - manufacturer=manufacturer, - MPN=MPN) - except IntegrityError: - manufacturer_part = None - raise ValidationError(f'ManufacturerPart linked to {self.part} from manufacturer {manufacturer.name}' - f'with part number {MPN} already exists!') - - if manufacturer_part: - self.manufacturer_part = manufacturer_part - - self.clean() - self.validate_unique() - - super().save(*args, **kwargs) - class Meta: unique_together = ('part', 'supplier', 'SKU') @@ -660,6 +647,10 @@ class SupplierPriceBreak(common.models.PriceBreak): currency: Reference to the currency of this pricebreak (leave empty for base currency) """ + @staticmethod + def get_api_url(): + return reverse('api-part-supplier-price-list') + part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks', verbose_name=_('Part'),) class Meta: diff --git a/InvenTree/company/serializers.py b/InvenTree/company/serializers.py index 1e97756987..e9f13d021d 100644 --- a/InvenTree/company/serializers.py +++ b/InvenTree/company/serializers.py @@ -2,6 +2,8 @@ JSON serializers for Company app """ +from django.utils.translation import ugettext_lazy as _ + from rest_framework import serializers from sql_util.utils import SubqueryCount @@ -15,6 +17,8 @@ from .models import Company from .models import ManufacturerPart, ManufacturerPartParameter from .models import SupplierPart, SupplierPriceBreak +from common.settings import currency_code_default, currency_code_mappings + class CompanyBriefSerializer(InvenTreeModelSerializer): """ Serializer for Company object (limited detail) """ @@ -58,6 +62,14 @@ class CompanySerializer(InvenTreeModelSerializer): parts_supplied = serializers.IntegerField(read_only=True) parts_manufactured = serializers.IntegerField(read_only=True) + currency = serializers.ChoiceField( + choices=currency_code_mappings(), + initial=currency_code_default, + help_text=_('Default currency used for this supplier'), + label=_('Currency Code'), + required=True, + ) + class Meta: model = Company fields = [ @@ -70,6 +82,7 @@ class CompanySerializer(InvenTreeModelSerializer): 'phone', 'address', 'email', + 'currency', 'contact', 'link', 'image', @@ -83,7 +96,9 @@ class CompanySerializer(InvenTreeModelSerializer): class ManufacturerPartSerializer(InvenTreeModelSerializer): - """ Serializer for ManufacturerPart object """ + """ + Serializer for ManufacturerPart object + """ part_detail = PartBriefSerializer(source='part', many=False, read_only=True) @@ -93,8 +108,8 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): def __init__(self, *args, **kwargs): - part_detail = kwargs.pop('part_detail', False) - manufacturer_detail = kwargs.pop('manufacturer_detail', False) + part_detail = kwargs.pop('part_detail', True) + manufacturer_detail = kwargs.pop('manufacturer_detail', True) prettify = kwargs.pop('pretty', False) super(ManufacturerPartSerializer, self).__init__(*args, **kwargs) @@ -167,9 +182,10 @@ class SupplierPartSerializer(InvenTreeModelSerializer): def __init__(self, *args, **kwargs): - part_detail = kwargs.pop('part_detail', False) - supplier_detail = kwargs.pop('supplier_detail', False) - manufacturer_detail = kwargs.pop('manufacturer_detail', False) + part_detail = kwargs.pop('part_detail', True) + supplier_detail = kwargs.pop('supplier_detail', True) + manufacturer_detail = kwargs.pop('manufacturer_detail', True) + prettify = kwargs.pop('pretty', False) super(SupplierPartSerializer, self).__init__(*args, **kwargs) @@ -192,45 +208,29 @@ class SupplierPartSerializer(InvenTreeModelSerializer): MPN = serializers.StringRelatedField(source='manufacturer_part.MPN') - manufacturer_part = ManufacturerPartSerializer(read_only=True) + manufacturer_part_detail = ManufacturerPartSerializer(source='manufacturer_part', read_only=True) class Meta: model = SupplierPart fields = [ + 'description', + 'link', + 'manufacturer', + 'manufacturer_detail', + 'manufacturer_part', + 'manufacturer_part_detail', + 'MPN', + 'note', 'pk', + 'packaging', 'part', 'part_detail', 'pretty_name', + 'SKU', 'supplier', 'supplier_detail', - 'SKU', - 'manufacturer', - 'MPN', - 'manufacturer_detail', - 'manufacturer_part', - 'description', - 'link', ] - def create(self, validated_data): - """ Extract manufacturer data and process ManufacturerPart """ - - # Create SupplierPart - supplier_part = super().create(validated_data) - - # Get ManufacturerPart raw data (unvalidated) - manufacturer_id = self.initial_data.get('manufacturer', None) - MPN = self.initial_data.get('MPN', None) - - if manufacturer_id and MPN: - kwargs = { - 'manufacturer': manufacturer_id, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - return supplier_part - class SupplierPriceBreakSerializer(InvenTreeModelSerializer): """ Serializer for SupplierPriceBreak object """ @@ -239,6 +239,12 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer): price = serializers.CharField() + price_currency = serializers.ChoiceField( + choices=currency_code_mappings(), + default=currency_code_default, + label=_('Currency'), + ) + class Meta: model = SupplierPriceBreak fields = [ @@ -246,4 +252,5 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer): 'part', 'quantity', 'price', + 'price_currency', ] diff --git a/InvenTree/company/templates/company/assigned_stock.html b/InvenTree/company/templates/company/assigned_stock.html deleted file mode 100644 index d64719407b..0000000000 --- a/InvenTree/company/templates/company/assigned_stock.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/navbar.html" with tab="assigned" %} -{% endblock %} - -{% block heading %} -{% trans "Assigned Stock" %} -{% endblock %} - -{% block details %} - -
                -
                - -
                -
                - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTable($("#stock-table"), { - params: { - customer: {{ company.id }}, - part_detail: true, - location_detail: true, - }, - url: "{% url 'api-stock-list' %}", - filterKey: "customerstock", -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/company_base.html b/InvenTree/company/templates/company/company_base.html index a276f5df4f..3b8f1e7734 100644 --- a/InvenTree/company/templates/company/company_base.html +++ b/InvenTree/company/templates/company/company_base.html @@ -71,6 +71,17 @@ {{ company.website }}{% include "clip.html"%} {% endif %} + + + {% trans "Currency" %} + + {% if company.currency %} + {{ company.currency }} + {% else %} + {% trans "Uses default currency" %} + {% endif %} + + {% if company.address %} @@ -99,6 +110,22 @@ {{ company.contact }}{% include "clip.html"%} {% endif %} + + + + {%trans "Manufacturer" %} + {% include "yesnolabel.html" with value=company.is_manufacturer %} + + + + {% trans "Supplier" %} + {% include 'yesnolabel.html' with value=company.is_supplier %} + + + + {% trans "Customer" %} + {% include 'yesnolabel.html' with value=company.is_customer %} + {% endblock %} @@ -111,32 +138,31 @@ }); $('#company-edit').click(function() { - launchModalForm( - "{% url 'company-edit' company.id %}", - { - reload: true - }); + editCompany({{ company.id }}); }); $("#company-order-2").click(function() { - launchModalForm("{% url 'po-create' %}", - { - data: { - supplier: {{ company.id }}, - }, - follow: true, + createPurchaseOrder({ + supplier: {{ company.pk }}, }); }); - $('#company-delete').click(function() { - launchModalForm( - "{% url 'company-delete' company.id %}", - { - redirect: "{% url 'company-index' %}" - }); + constructForm('{% url "api-company-detail" company.pk %}', { + method: 'DELETE', + title: '{% trans "Delete Company" %}', + redirect: '{% url "company-index" %}', + }); }); + function reloadImage(data) { + if (data.image) { + $('#company-image').attr('src', data.image); + } else { + location.reload(); + } + } + enableDragAndDrop( "#company-thumb", "{% url 'api-company-detail' company.id %}", @@ -144,12 +170,7 @@ label: 'image', method: 'PATCH', success: function(data, status, xhr) { - - if (data.image) { - $('#company-image').attr('src', data.image); - } else { - location.reload(); - } + reloadImage(data); } } ); @@ -161,10 +182,18 @@ {% endif %} $("#company-image-upload").click(function() { - launchModalForm( - "{% url 'company-image' company.id %}", + + constructForm( + '{% url "api-company-detail" company.pk %}', { - reload: true + method: 'PATCH', + fields: { + image: {}, + }, + title: '{% trans "Upload Image" %}', + onSuccess: function(data) { + reloadImage(data); + } } ); }); diff --git a/InvenTree/company/templates/company/delete.html b/InvenTree/company/templates/company/delete.html deleted file mode 100644 index 3236a7a58d..0000000000 --- a/InvenTree/company/templates/company/delete.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "modal_delete_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} - -{% blocktrans with company.name as name %}Are you sure you want to delete company '{{ name }}'?{% endblocktrans %} - -
                - -{% if company.supplied_part_count > 0 %} -

                {% blocktrans with company.supplied_part_count as count %}There are {{ count }} parts sourced from this company.
                -If this supplier is deleted, these supplier part entries will also be deleted.{% endblocktrans %}

                -
                  -{% for part in company.parts.all %} -
                • {{ part.SKU }} - {{ part.part.full_name }}
                • -{% endfor %} -
                -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 9c3cbfb84a..4a9ac43758 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -1,79 +1,403 @@ {% extends "company/company_base.html" %} {% load static %} {% load i18n %} +{% load markdownify %} {% block menubar %} {% include 'company/navbar.html' with tab='details' %} {% endblock %} -{% block heading %} -{% trans "Company Details" %} -{% endblock %} +{% block page_content %} -{% block details %} -
                -
                - - - - - - - - - {% if company.description %} - - - - - - {% endif %} - - - - - - - - - - +
                + +
                + +
                + +
                + + + {% endif %} + +
                {% trans "Company Name" %}{{ company.name }}{% include "clip.html"%}
                {% trans "Description" %}{{ company.description }}{% include "clip.html"%}
                {% trans "Website" %} - {% if company.website %}{{ company.website }}{% include "clip.html"%} - {% else %}{% trans "No website specified" %} +
                +
                +

                {% trans "Supplier Parts" %}

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

                {% trans "Manufacturer Parts" %}

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

                {% trans "Supplier Stock" %}

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

                {% trans "Purchase Orders" %}

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

                {% trans "Sales Orders" %}

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

                {% trans "Assigned Stock" %}

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

                {% trans "Company Notes" %}

                +
                +
                +
                + +
                +
                +
                +
                +
                + {% if company.notes %} + {{ company.notes | markdownify }} + {% endif %}
                {% endblock %} + {% block js_ready %} {{ block.super }} + $('#edit-notes').click(function() { + constructForm('{% url "api-company-detail" company.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + loadStockTable($("#assigned-stock-table"), { + params: { + customer: {{ company.id }}, + part_detail: true, + location_detail: true, + }, + url: "{% url 'api-stock-list' %}", + filterKey: "customerstock", + }); + + {% if company.is_customer %} + loadSalesOrderTable("#sales-order-table", { + url: "{% url 'api-so-list' %}", + params: { + customer: {{ company.id }}, + } + }); + + $("#new-sales-order").click(function() { + + createSalesOrder({ + customer: {{ company.pk }}, + }); + }); + {% endif %} + + {% if company.is_supplier %} + loadPurchaseOrderTable("#purchase-order-table", { + url: "{% url 'api-po-list' %}", + params: { + supplier: {{ company.id }}, + } + }); + + function newOrder() { + createPurchaseOrder({ + supplier: {{ company.pk }}, + }); + } + + $("#company-order").click(function() { + newOrder(); + }); + + $("#company-order2").click(function() { + newOrder(); + }); + + {% endif %} + + loadStockTable($('#stock-table'), { + url: "{% url 'api-stock-list' %}", + params: { + company: {{ company.id }}, + part_detail: true, + supplier_part_detail: true, + location_detail: true, + }, + buttons: [ + '#stock-options', + ], + filterKey: "companystock", + }); + + $("#stock-export").click(function() { + exportStock({ + supplier: {{ company.id }} + }); + }); + + {% if company.is_manufacturer %} + + $("#manufacturer-part-create").click(function () { + + createManufacturerPart({ + manufacturer: {{ company.pk }}, + onSuccess: function() { + $("#part-table").bootstrapTable("refresh"); + } + }); + }); + + loadManufacturerPartTable( + "#part-table", + "{% url 'api-manufacturer-part-list' %}", + { + params: { + part_detail: true, + manufacturer_detail: true, + manufacturer: {{ company.id }}, + }, + } + ); + + linkButtonsToSelection($("#manufacturer-table"), ['#table-options']); + + $("#multi-part-delete").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + deleteManufacturerParts(selections, { + onSuccess: function() { + $("#part-table").bootstrapTable("refresh"); + } + }); + }); + + $("#multi-part-order").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.part); + }); + + launchModalForm("/order/purchase-order/order-parts/", { + data: { + parts: parts, + }, + }); + }); + + {% endif %} + + {% if company.is_supplier %} + + function reloadSupplierPartTable() { + $('#supplier-part-table').bootstrapTable('refresh'); + } + + $("#supplier-part-create").click(function () { + + createSupplierPart({ + supplier: {{ company.pk }}, + onSuccess: reloadSupplierPartTable, + }); + }); + + loadSupplierPartTable( + "#supplier-part-table", + "{% url 'api-supplier-part-list' %}", + { + params: { + part_detail: true, + supplier_detail: true, + manufacturer_detail: true, + supplier: {{ company.id }}, + }, + } + ); + + {% endif %} + + $("#multi-part-delete").click(function() { + var selections = $("#supplier-part-table").bootstrapTable("getSelections"); + + var requests = []; + + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + $('#supplier-part-table').bootstrapTable('refresh'); + }); + } + } + ); + }); + + $("#multi-part-order").click(function() { + var selections = $("#part-table").bootstrapTable("getSelections"); + + var parts = []; + + selections.forEach(function(item) { + parts.push(item.part); + }); + + launchModalForm("/order/purchase-order/order-parts/", { + data: { + parts: parts, + }, + }); + }); + + attachNavCallbacks({ + name: 'company', + default: 'company-stock' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_manufacturer_part.html b/InvenTree/company/templates/company/detail_manufacturer_part.html deleted file mode 100644 index 902d456eaf..0000000000 --- a/InvenTree/company/templates/company/detail_manufacturer_part.html +++ /dev/null @@ -1,127 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='manufacturer_parts' %} -{% endblock %} - -{% block heading %} -{% trans "Manufacturer Parts" %} -{% endblock %} - - -{% block details %} - -{% if roles.purchase_order.change %} -
                -
                -
                - {% if roles.purchase_order.add %} - - {% endif %} -
                - -
                -
                -
                - -
                -
                -
                -{% endif %} - -
                - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $("#manufacturer-part-create").click(function () { - launchModalForm( - "{% url 'manufacturer-part-create' %}", - { - data: { - manufacturer: {{ company.id }}, - }, - reload: true, - secondary: [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create new Part" %}', - url: "{% url 'part-create' %}" - }, - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new Manufacturer" %}', - url: "{% url 'manufacturer-create' %}", - }, - ] - }); - }); - - loadManufacturerPartTable( - "#part-table", - "{% url 'api-manufacturer-part-list' %}", - { - params: { - part_detail: true, - manufacturer_detail: true, - company: {{ company.id }}, - }, - } - ); - - $("#multi-part-delete").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - var url = "{% url 'manufacturer-part-delete' %}" - - launchModalForm(url, { - data: { - parts: parts, - }, - reload: true, - }); - }); - - $("#multi-part-order").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.part); - }); - - launchModalForm("/order/purchase-order/order-parts/", { - data: { - parts: parts, - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_stock.html b/InvenTree/company/templates/company/detail_stock.html deleted file mode 100644 index f10a99ba5a..0000000000 --- a/InvenTree/company/templates/company/detail_stock.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/navbar.html" with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Stock" %} -{% endblock %} - -{% block details %} - -{% include "stock_table.html" %} - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - loadStockTable($('#stock-table'), { - url: "{% url 'api-stock-list' %}", - params: { - company: {{ company.id }}, - part_detail: true, - supplier_detail: true, - location_detail: true, - }, - buttons: [ - '#stock-options', - ], - filterKey: "companystock", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&supplier={{ company.id }}"; - - location.href = url; - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/detail_supplier_part.html b/InvenTree/company/templates/company/detail_supplier_part.html deleted file mode 100644 index bf92f96843..0000000000 --- a/InvenTree/company/templates/company/detail_supplier_part.html +++ /dev/null @@ -1,128 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='supplier_parts' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Parts" %} -{% endblock %} - - -{% block details %} -{% if roles.purchase_order.change %} -
                -
                -
                - {% if roles.purchase_order.add %} - - {% endif %} -
                - -
                -
                -
                - -
                -
                -
                -{% endif %} - - -
                - -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $("#supplier-part-create").click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - data: { - supplier: {{ company.id }}, - }, - reload: true, - secondary: [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create new Part" %}', - url: "{% url 'part-create' %}" - }, - { - field: 'supplier', - label: "{% trans 'New Supplier' %}", - title: "{% trans 'Create new Supplier' %}", - url: "{% url 'supplier-create' %}", - }, - ] - }); - }); - - loadSupplierPartTable( - "#part-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part_detail: true, - supplier_detail: true, - manufacturer_detail: true, - company: {{ company.id }}, - }, - } - ); - - $("#multi-part-delete").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - var url = "{% url 'supplier-part-delete' %}" - - launchModalForm(url, { - data: { - parts: parts, - }, - reload: true, - }); - }); - - $("#multi-part-order").click(function() { - var selections = $("#part-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.part); - }); - - launchModalForm("/order/purchase-order/order-parts/", { - data: { - parts: parts, - }, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/index.html b/InvenTree/company/templates/company/index.html index 3a3168f24e..672d82fdb7 100644 --- a/InvenTree/company/templates/company/index.html +++ b/InvenTree/company/templates/company/index.html @@ -15,10 +15,10 @@ {% if pagetype == 'manufacturers' and roles.purchase_order.add or pagetype == 'suppliers' and roles.purchase_order.add or pagetype == 'customers' and roles.sales_order.add %}
                +
                -
                {% endif %} @@ -29,9 +29,18 @@ {% endblock %} {% block js_ready %} {{ block.super }} - $('#new-company').click(function () { - launchModalForm("{{ create_url }}", { - follow: true + + $('#new-company').click(function() { + + var fields = companyFormFields(); + + // Field overrides + fields.is_supplier.value = {% if pagetype == 'suppliers' %}true{% else %}false{% endif %}; + fields.is_manufacturer.value = {% if pagetype == 'manufacturers' %}true{% else %}false{% endif %}; + fields.is_customer.value = {% if pagetype == 'customers' %}true{% else %}false{% endif %}; + + createCompany({ + fields: fields, }); }); diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html new file mode 100644 index 0000000000..94ff64440f --- /dev/null +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -0,0 +1,321 @@ +{% extends "two_column.html" %} +{% load static %} +{% load i18n %} + +{% block page_title %} +InvenTree | {% trans "Manufacturer Part" %} +{% endblock %} + +{% block menubar %} +{% include "company/manufacturer_part_navbar.html" %} +{% endblock %} + +{% block thumbnail %} + +{% endblock %} + +{% block page_data %} +

                {% trans "Manufacturer Part" %}

                +
                +

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

                +

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

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

                {% trans "Manufacturer Part Details" %}

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

                {% trans "Suppliers" %}

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

                {% trans "Parameters" %}

                +
                +
                +
                +
                + +
                + + +
                +
                +
                + +
                +
                +
                + +{% endblock %} + + +{% block js_ready %} +{{ block.super }} + +enableNavbar({ + label: 'manufacturer-part', + toggleId: '#manufacturer-part-menu-toggle' +}); + +function reloadParameters() { + $("#parameter-table").bootstrapTable("refresh"); +} + +$('#parameter-create').click(function() { + + constructForm('{% url "api-manufacturer-part-parameter-list" %}', { + method: 'POST', + fields: { + name: {}, + value: {}, + units: {}, + manufacturer_part: { + value: {{ part.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Parameter" %}', + onSuccess: reloadParameters + }); +}); + +function reloadSupplierPartTable() { + $('#supplier-table').bootstrapTable('refresh'); +} + +$('#supplier-create').click(function () { + createSupplierPart({ + manufacturer_part: {{ part.pk }}, + part: {{ part.part.pk }}, + onSuccess: reloadSupplierPartTable, + }); +}); + +$("#supplier-part-delete").click(function() { + + var selections = $("#supplier-table").bootstrapTable("getSelections"); + + var requests = []; + + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + reloadSupplierPartTable(); + }); + } + } + ); +}); + +$("#multi-parameter-delete").click(function() { + + var selections = $("#parameter-table").bootstrapTable("getSelections"); + + var text = ` +
                +

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

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

                {% trans "Manufacturer Part" %}

                -
                -

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

                -

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

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

                {% trans "Manufacturer Part Details" %}

                - - - - - - - - {% if part.description %} - - - - - - {% endif %} - {% if part.link %} - - - - - - {% endif %} - - - - - - - - - -
                {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }}{% include "clip.html"%} - {% endif %} -
                {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
                {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
                {% trans "Manufacturer" %}{{ part.manufacturer.name }}{% include "clip.html"%}
                {% trans "MPN" %}{{ part.MPN }}{% include "clip.html"%}
                -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableNavbar({ - label: 'manufacturer-part', - toggleId: '#manufacturer-part-menu-toggle' -}) - -$('#order-part, #order-part2').click(function() { - launchModalForm( - "{% url 'order-parts' %}", - { - data: { - part: {{ part.part.id }}, - }, - reload: true, - }, - ); -}); - -$('#edit-part').click(function () { - launchModalForm( - "{% url 'manufacturer-part-edit' part.id %}", - { - reload: true - } - ); -}); - -$('#delete-part').click(function() { - launchModalForm( - "{% url 'manufacturer-part-delete' %}?part={{ part.id }}", - { - redirect: "{% url 'company-detail-manufacturer-parts' part.manufacturer.id %}" - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_create.html b/InvenTree/company/templates/company/manufacturer_part_create.html deleted file mode 100644 index 21c23f9075..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_create.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} -{{ block.super }} - -{% if part %} -
                - {% include "hover_image.html" with image=part.image %} - {{ part.full_name}} -
                - {{ part.description }} -
                -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_delete.html b/InvenTree/company/templates/company/manufacturer_part_delete.html deleted file mode 100644 index 6c96c978d4..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_delete.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -
                - {% trans "Are you sure you want to delete the following Manufacturer Parts?" %} -
                -{% for part in parts %} - -{% endfor %} - -{% endblock %} - -{% block form_data %} - -{% for part in parts %} - - - - - - - - -
                - {% include "hover_image.html" with image=part.part.image %} - {{ part.part.full_name }} - - {% include "hover_image.html" with image=part.manufacturer.image %} - {{ part.manufacturer.name }} - - {{ part.MPN }} -
                -{% if part.supplier_parts.all|length > 0 %} -
                -

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

                -
                  - {% for spart in part.supplier_parts.all %} -
                • {{ spart.supplier.name }} - {{ spart.SKU }}
                • - {% endfor %} -
                -
                -{% endif %} -{% endfor %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_detail.html b/InvenTree/company/templates/company/manufacturer_part_detail.html deleted file mode 100644 index 430072a834..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_detail.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "company/manufacturer_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/manufacturer_part_navbar.html" with tab='details' %} -{% endblock %} - -{% block heading %} -{% trans "Manufacturer Part Details" %} -{% endblock %} - - -{% block details %} - - - - - - - - -{% if part.link %} - -{% endif %} -
                {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }} - {% endif %} -
                {% trans "Manufacturer" %}{{ part.manufacturer.name }}
                {% trans "MPN" %}{{ part.MPN }}
                {% trans "External Link" %}{{ part.link }}
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/manufacturer_part_navbar.html b/InvenTree/company/templates/company/manufacturer_part_navbar.html index 3eae30afaf..893374858f 100644 --- a/InvenTree/company/templates/company/manufacturer_part_navbar.html +++ b/InvenTree/company/templates/company/manufacturer_part_navbar.html @@ -8,8 +8,15 @@
              • -
              • - +
              • + + + {% trans "Parameters" %} + +
              • + +
              • + {% trans "Suppliers" %} @@ -22,7 +29,7 @@ {% trans "Stock" %}
              • - +
              • diff --git a/InvenTree/company/templates/company/manufacturer_part_suppliers.html b/InvenTree/company/templates/company/manufacturer_part_suppliers.html deleted file mode 100644 index 9f445ec215..0000000000 --- a/InvenTree/company/templates/company/manufacturer_part_suppliers.html +++ /dev/null @@ -1,134 +0,0 @@ -{% extends "company/manufacturer_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/manufacturer_part_navbar.html" with tab='suppliers' %} -{% endblock %} - -{% block heading %} -{% trans "Suppliers" %} -{% endblock %} - -{% block details %} - - - -
                - -{% endblock %} - -{% block post_content_panels %} - -
                -
                -

                {% trans "Parameters" %}

                -
                -
                -
                -
                - -
                - -
                -
                -
                - -
                -
                -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -$('#parameter-create').click(function() { - launchModalForm( - "{% url 'manufacturer-part-parameter-create' %}", - { - data: { - manufacturer_part: {{ part.id }}, - } - } - ); -}); - -$('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - manufacturer_part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - url: "{% url 'supplier-create' %}" - }, - ] - }); -}); - -$("#supplier-part-delete").click(function() { - - var selections = $("#supplier-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); -}); - -loadSupplierPartTable( - "#supplier-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part: {{ part.part.id }}, - manufacturer_part: {{ part.id }}, - part_detail: false, - supplier_detail: true, - manufacturer_detail: false, - }, - } -); - -loadManufacturerPartParameterTable( - "#parameter-table", - "{% url 'api-manufacturer-part-parameter-list' %}", - { - params: { - manufacturer_part: {{ part.id }}, - } - } -); - -linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/navbar.html b/InvenTree/company/templates/company/navbar.html index 715d448b0f..b652d6b603 100644 --- a/InvenTree/company/templates/company/navbar.html +++ b/InvenTree/company/templates/company/navbar.html @@ -9,25 +9,18 @@
              • -
              • - - - {% trans "Details" %} - -
              • - {% if company.is_manufacturer %} -
              • - +
              • + {% trans "Manufactured Parts" %}
              • {% endif %} - {% if company.is_supplier or company.is_manufacturer %} -
              • - + {% if company.is_supplier %} +
              • + {% trans "Supplied Parts" %} @@ -35,8 +28,8 @@ {% endif %} {% if company.is_manufacturer or company.is_supplier %} -
              • - +
              • + {% trans "Stock" %} @@ -44,8 +37,8 @@ {% endif %} {% if company.is_supplier %} -
              • - +
              • + {% trans "Purchase Orders" %} @@ -53,22 +46,22 @@ {% endif %} {% if company.is_customer %} -
              • - +
              • + {% trans "Sales Orders" %}
              • -
              • - +
              • + {% trans "Assigned Stock" %}
              • {% endif %} -
              • - +
              • + {% trans "Notes" %} diff --git a/InvenTree/company/templates/company/notes.html b/InvenTree/company/templates/company/notes.html deleted file mode 100644 index 6b0e65e2d0..0000000000 --- a/InvenTree/company/templates/company/notes.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Company Notes" %} -{% if not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
                - {% csrf_token %} - - {{ form }} -
                - - -
                - -{{ form.media }} - -{% else %} - -{{ company.notes | markdownify }} -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'company-notes' company.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/purchase_orders.html b/InvenTree/company/templates/company/purchase_orders.html deleted file mode 100644 index 0403c8cc59..0000000000 --- a/InvenTree/company/templates/company/purchase_orders.html +++ /dev/null @@ -1,61 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'company/navbar.html' with tab='po' %} -{% endblock %} - -{% block heading %} -{% trans "Purchase Orders" %} -{% endblock %} - -{% block details %} - -{% if roles.purchase_order.add %} -
                -
                - -
                - -
                -
                -
                -{% endif %} - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPurchaseOrderTable("#purchase-order-table", { - url: "{% url 'api-po-list' %}", - params: { - supplier: {{ company.id }}, - } - }); - - - function newOrder() { - launchModalForm("{% url 'po-create' %}", - { - data: { - supplier: {{ company.id }}, - }, - follow: true, - }); - } - - $("#company-order").click(function() { - newOrder(); - }); - - $("#company-order2").click(function() { - newOrder(); - }); - -{% endblock %} diff --git a/InvenTree/company/templates/company/sales_orders.html b/InvenTree/company/templates/company/sales_orders.html deleted file mode 100644 index e8585e2caa..0000000000 --- a/InvenTree/company/templates/company/sales_orders.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends "company/company_base.html" %} -{% load static %} -{% load i18n %} - - -{% block menubar %} -{% include 'company/navbar.html' with tab='so' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Orders" %} -{% endblock %} - -{% block details %} - -{% if roles.sales_order.add %} -
                -
                - -
                - -
                -
                -
                -{% endif %} - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadSalesOrderTable("#sales-order-table", { - url: "{% url 'api-so-list' %}", - params: { - customer: {{ company.id }}, - } - }); - - $("#new-sales-order").click(function() { - launchModalForm( - "{% url 'so-create' %}", - { - data: { - customer: {{ company.id }}, - }, - follow: true, - }, - ); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html new file mode 100644 index 0000000000..ec85d85af9 --- /dev/null +++ b/InvenTree/company/templates/company/supplier_part.html @@ -0,0 +1,345 @@ +{% extends "two_column.html" %} +{% load static %} +{% load i18n %} +{% load inventree_extras %} + +{% block page_title %} +{% inventree_title %} | {% trans "Supplier Part" %} +{% endblock %} + +{% block menubar %} +{% include "company/supplier_part_navbar.html" %} +{% endblock %} + +{% block thumbnail %} + +{% endblock %} + +{% block page_data %} +

                {% trans "Supplier Part" %}

                +
                +

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

                +

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

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

                {% trans "Supplier Part Details" %}

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

                {% trans "Supplier Part Stock" %}

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

                {% trans "Supplier Part Orders" %}

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

                {% trans "Pricing Information" %}

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

                {% trans "Supplier Part" %}

                -
                -

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

                -

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

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

                {% trans "Supplier Part Details" %}

                - - - - - - - - {% if part.description %} - - - - - - {% endif %} - {% if part.link %} - - - - - - {% endif %} - - - - - - - - - - {% if part.manufacturer_part.manufacturer %} - - - - - - {% endif %} - {% if part.manufacturer_part.MPN %} - - - - - - {% endif %} - {% if part.packaging %} - - - - - - {% endif %} - {% if part.note %} - - - - - - {% endif %} -
                {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }}{% include "clip.html"%} - {% endif %} -
                {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
                {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
                {% trans "Supplier" %}{{ part.supplier.name }}{% include "clip.html"%}
                {% trans "SKU" %}{{ part.SKU }}{% include "clip.html"%}
                {% trans "Manufacturer" %} - {{ part.manufacturer_part.manufacturer.name }}{% include "clip.html"%}
                {% trans "MPN" %}{{ part.manufacturer_part.MPN }}{% include "clip.html"%}
                {% trans "Packaging" %}{{ part.packaging }}{% include "clip.html"%}
                {% trans "Note" %}{{ part.note }}{% include "clip.html"%}
                -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableNavbar({ - label: 'supplier-part', - toggleId: '#supplier-part-menu-toggle' -}) - -$('#order-part, #order-part2').click(function() { - launchModalForm( - "{% url 'order-parts' %}", - { - data: { - part: {{ part.part.id }}, - }, - reload: true, - }, - ); -}); - -$('#edit-part').click(function () { - launchModalForm( - "{% url 'supplier-part-edit' part.id %}", - { - reload: true - } - ); -}); - -$('#delete-part').click(function() { - launchModalForm( - "{% url 'supplier-part-delete' %}?part={{ part.id }}", - { - redirect: "{% url 'company-detail-supplier-parts' part.supplier.id %}" - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_create.html b/InvenTree/company/templates/company/supplier_part_create.html deleted file mode 100644 index 21c23f9075..0000000000 --- a/InvenTree/company/templates/company/supplier_part_create.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} -{{ block.super }} - -{% if part %} -
                - {% include "hover_image.html" with image=part.image %} - {{ part.full_name}} -
                - {{ part.description }} -
                -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_delete.html b/InvenTree/company/templates/company/supplier_part_delete.html deleted file mode 100644 index 40d9ce42de..0000000000 --- a/InvenTree/company/templates/company/supplier_part_delete.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -{% trans "Are you sure you want to delete the following Supplier Parts?" %} - -
                -{% endblock %} - -{% block form_data %} - -{% for part in parts %} - - - - - - - -{% endfor %} -
                - {% include "hover_image.html" with image=part.part.image %} - {{ part.part.full_name }} - - {% include "hover_image.html" with image=part.supplier.image %} - {{ part.supplier.name }} - - {{ part.SKU }} -
                - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_detail.html b/InvenTree/company/templates/company/supplier_part_detail.html deleted file mode 100644 index fb73ca06f4..0000000000 --- a/InvenTree/company/templates/company/supplier_part_detail.html +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='details' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Details" %} -{% endblock %} - - -{% block details %} - - - - - - - - -{% if part.link %} - -{% endif %} -{% if part.description %} - -{% endif %} -{% if part.manufacturer %} - - -{% endif %} -{% if part.note %} - -{% endif %} -
                {% trans "Internal Part" %} - {% if part.part %} - {{ part.part.full_name }} - {% endif %} -
                {% trans "Supplier" %}{{ part.supplier.name }}
                {% trans "SKU" %}{{ part.SKU }}
                {% trans "External Link" %}{{ part.link }}
                {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
                {% trans "Manufacturer" %}{{ part.manufacturer }}{% include "clip.html"%}
                {% trans "MPN" %}{{ part.MPN }}{% include "clip.html"%}
                {% trans "Note" %}{{ part.note }}{% include "clip.html"%}
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_navbar.html b/InvenTree/company/templates/company/supplier_part_navbar.html index e52c1798ba..4f7783701a 100644 --- a/InvenTree/company/templates/company/supplier_part_navbar.html +++ b/InvenTree/company/templates/company/supplier_part_navbar.html @@ -9,22 +9,22 @@
              • -
              • - +
              • + {% trans "Stock" %}
              • -
              • - +
              • + {% trans "Orders" %}
              • -
              • - +
              • + {% trans "Pricing" %} diff --git a/InvenTree/company/templates/company/supplier_part_orders.html b/InvenTree/company/templates/company/supplier_part_orders.html deleted file mode 100644 index 05e425fc97..0000000000 --- a/InvenTree/company/templates/company/supplier_part_orders.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='orders' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Orders" %} -{% endblock %} - -{% block details %} -{% if roles.purchase_order.add %} -
                -
                - -
                -
                -{% endif %} - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPurchaseOrderTable($("#purchase-order-table"), { - url: "{% url 'api-po-list' %}?supplier_part={{ part.id }}", -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_pricing.html b/InvenTree/company/templates/company/supplier_part_pricing.html deleted file mode 100644 index 9da3f3df7e..0000000000 --- a/InvenTree/company/templates/company/supplier_part_pricing.html +++ /dev/null @@ -1,111 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='pricing' %} -{% endblock %} - -{% block heading %} -{% trans "Pricing Information" %} -{% endblock %} - -{% block details %} - -{% if roles.purchase_order.add %} -
                - -
                -{% endif %} - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -function reloadPriceBreaks() { - $("#price-break-table").bootstrapTable("refresh"); -} - -$('#price-break-table').inventreeTable({ - name: 'buypricebreaks', - formatNoMatches: function() { return "{% trans "No price break information found" %}"; }, - queryParams: { - part: {{ part.id }}, - }, - url: "{% url 'api-part-supplier-price' %}", - onPostBody: function() { - var table = $('#price-break-table'); - - table.find('.button-price-break-delete').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/price-break/${pk}/delete/`, - { - success: reloadPriceBreaks - } - ); - }); - - table.find('.button-price-break-edit').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/price-break/${pk}/edit/`, - { - success: reloadPriceBreaks - } - ); - }); - }, - columns: [ - { - field: 'pk', - title: 'ID', - visible: false, - switchable: false, - }, - { - field: 'quantity', - title: '{% trans "Quantity" %}', - sortable: true, - }, - { - field: 'price', - title: '{% trans "Price" %}', - sortable: true, - formatter: function(value, row, index) { - var html = value; - - html += `
                ` - - html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}'); - html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}'); - - html += `
                `; - - return html; - } - }, - ] -}); - -$('#new-price-break').click(function() { - launchModalForm("{% url 'price-break-create' %}", - { - reload: true, - data: { - part: {{ part.id }}, - } - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/supplier_part_stock.html b/InvenTree/company/templates/company/supplier_part_stock.html deleted file mode 100644 index 1187b95bca..0000000000 --- a/InvenTree/company/templates/company/supplier_part_stock.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "company/supplier_part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "company/supplier_part_navbar.html" with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Supplier Part Stock" %} -{% endblock %} - -{% block details %} -{% include "stock_table.html" %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadStockTable($("#stock-table"), { - params: { - supplier_part: {{ part.id }}, - location_detail: true, - part_detail: false, - }, - groupByField: 'location', - buttons: ['#stock-options'], - url: "{% url 'api-stock-list' %}", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&supplier_part={{ part.id }}"; - - location.href = url; - }, - }); - }); - - $("#item-create").click(function() { - createNewStockItem({ - data: { - part: {{ part.part.id }}, - supplier_part: {{ part.id }}, - }, - reload: true, - }); - }); - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/test_api.py b/InvenTree/company/test_api.py index dd42b97801..a915ad1bf5 100644 --- a/InvenTree/company/test_api.py +++ b/InvenTree/company/test_api.py @@ -20,7 +20,7 @@ class CompanyTest(InvenTreeAPITestCase): super().setUp() - Company.objects.create(name='ACME', description='Supplier', is_customer=False, is_supplier=True) + self.acme = Company.objects.create(name='ACME', description='Supplier', is_customer=False, is_supplier=True) Company.objects.create(name='Drippy Cup Co.', description='Customer', is_customer=True, is_supplier=False) Company.objects.create(name='Sippy Cup Emporium', description='Another supplier') @@ -44,7 +44,11 @@ class CompanyTest(InvenTreeAPITestCase): self.assertEqual(len(response.data), 2) def test_company_detail(self): - url = reverse('api-company-detail', kwargs={'pk': 1}) + """ + Tests for the Company detail endpoint + """ + + url = reverse('api-company-detail', kwargs={'pk': self.acme.pk}) response = self.get(url) self.assertEqual(response.data['name'], 'ACME') @@ -52,22 +56,93 @@ class CompanyTest(InvenTreeAPITestCase): # Change the name of the company # Note we should not have the correct permissions (yet) data = response.data - data['name'] = 'ACMOO' response = self.client.patch(url, data, format='json', expected_code=400) self.assignRole('company.change') + # Update the name and set the currency to a valid value + data['name'] = 'ACMOO' + data['currency'] = 'NZD' + response = self.client.patch(url, data, format='json', expected_code=200) self.assertEqual(response.data['name'], 'ACMOO') + self.assertEqual(response.data['currency'], 'NZD') def test_company_search(self): - # Test search functionality in company list + """ + Test search functionality in company list + """ + url = reverse('api-company-list') data = {'search': 'cup'} response = self.get(url, data) self.assertEqual(len(response.data), 2) + def test_company_create(self): + """ + Test that we can create a company via the API! + """ + + url = reverse('api-company-list') + + # Name is required + response = self.post( + url, + { + 'description': 'A description!', + }, + expected_code=400 + ) + + # Minimal example, checking default values + response = self.post( + url, + { + 'name': 'My API Company', + 'description': 'A company created via the API', + }, + expected_code=201 + ) + + self.assertTrue(response.data['is_supplier']) + self.assertFalse(response.data['is_customer']) + self.assertFalse(response.data['is_manufacturer']) + + self.assertEqual(response.data['currency'], 'USD') + + # Maximal example, specify values + response = self.post( + url, + { + 'name': "Another Company", + 'description': "Also created via the API!", + 'currency': 'AUD', + 'is_supplier': False, + 'is_manufacturer': True, + 'is_customer': True, + }, + expected_code=201 + ) + + self.assertEqual(response.data['currency'], 'AUD') + self.assertFalse(response.data['is_supplier']) + self.assertTrue(response.data['is_customer']) + self.assertTrue(response.data['is_manufacturer']) + + # Attempt to create with invalid currency + response = self.post( + url, + { + 'name': "A name", + 'description': 'A description', + 'currency': 'POQD', + }, + expected_code=400 + ) + + self.assertTrue('currency' in response.data) + class ManufacturerTest(InvenTreeAPITestCase): """ @@ -115,6 +190,9 @@ class ManufacturerTest(InvenTreeAPITestCase): self.assertEqual(len(response.data), 2) def test_manufacturer_part_detail(self): + """ + Tests for the ManufacturerPart detail endpoint + """ url = reverse('api-manufacturer-part-detail', kwargs={'pk': 1}) response = self.get(url) @@ -140,19 +218,32 @@ class ManufacturerTest(InvenTreeAPITestCase): def test_supplier_part_create(self): url = reverse('api-supplier-part-list') - # Create supplier part + # Create a manufacturer part + response = self.post( + reverse('api-manufacturer-part-list'), + { + 'part': 1, + 'manufacturer': 7, + 'MPN': 'PART_NUMBER', + }, + expected_code=201 + ) + + pk = response.data['pk'] + + # Create a supplier part (associated with the new manufacturer part) data = { 'part': 1, 'supplier': 1, 'SKU': 'SKU_TEST', - 'manufacturer': 7, - 'MPN': 'PART_NUMBER', + 'manufacturer_part': pk, } + response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) # Check manufacturer part - manufacturer_part_id = int(response.data['manufacturer_part']['pk']) + manufacturer_part_id = int(response.data['manufacturer_part_detail']['pk']) url = reverse('api-manufacturer-part-detail', kwargs={'pk': manufacturer_part_id}) response = self.get(url) self.assertEqual(response.data['MPN'], 'PART_NUMBER') diff --git a/InvenTree/company/test_views.py b/InvenTree/company/test_views.py index cdb2d32af9..89968081c3 100644 --- a/InvenTree/company/test_views.py +++ b/InvenTree/company/test_views.py @@ -10,9 +10,6 @@ from django.urls import reverse from django.contrib.auth import get_user_model from django.contrib.auth.models import Group -from .models import ManufacturerPart -from .models import SupplierPart - class CompanyViewTestBase(TestCase): @@ -75,108 +72,6 @@ class CompanyViewTestBase(TestCase): return json_data, form_errors -class SupplierPartViewTests(CompanyViewTestBase): - """ - Tests for the SupplierPart views. - """ - - def test_supplier_part_create(self): - """ - Test the SupplierPartCreate view. - - This view allows some additional functionality, - specifically it allows the user to create a single-quantity price break - automatically, when saving the new SupplierPart model. - """ - - url = reverse('supplier-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many supplier parts are already in the database? - n = SupplierPart.objects.all().count() - - data = { - 'part': 1, - 'supplier': 1, - } - - # SKU is required! (form should fail) - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('SKU', None)) - - data['SKU'] = 'TEST-ME-123' - - (response, errors) = self.post(url, data, valid=True) - - # Check that the SupplierPart was created! - self.assertEqual(n + 1, SupplierPart.objects.all().count()) - - # Check that it was created *without* a price-break - supplier_part = SupplierPart.objects.get(pk=response['pk']) - - self.assertEqual(supplier_part.price_breaks.count(), 0) - - # Duplicate SKU is prohibited - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('__all__', None)) - - # Add with a different SKU, *and* a single-quantity price - data['SKU'] = 'TEST-ME-1234' - data['single_pricing_0'] = '123.4' - data['single_pricing_1'] = 'CAD' - - (response, errors) = self.post(url, data, valid=True) - - pk = response.get('pk') - - # Check that *another* SupplierPart was created - self.assertEqual(n + 2, SupplierPart.objects.all().count()) - - supplier_part = SupplierPart.objects.get(pk=pk) - - # Check that a price-break has been created! - self.assertEqual(supplier_part.price_breaks.count(), 1) - - price_break = supplier_part.price_breaks.first() - - self.assertEqual(price_break.quantity, 1) - - def test_supplier_part_delete(self): - """ - Test the SupplierPartDelete view - """ - - url = reverse('supplier-part-delete') - - # Get form using 'part' argument - response = self.client.get(url, {'part': '1'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Get form using 'parts' argument - response = self.client.get(url + '?parts[]=1&parts[]=2', HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # POST to delete two parts - n = SupplierPart.objects.count() - response = self.client.post( - url, - { - 'supplier-part-2': 'supplier-part-2', - 'supplier-part-3': 'supplier-part-3', - 'confirm_delete': True - }, - HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(response.status_code, 200) - - self.assertEqual(n - 2, SupplierPart.objects.count()) - - class CompanyViewTest(CompanyViewTestBase): """ Tests for various 'Company' views @@ -187,120 +82,3 @@ class CompanyViewTest(CompanyViewTestBase): response = self.client.get(reverse('company-index')) self.assertEqual(response.status_code, 200) - - def test_company_create(self): - """ - Test the view for creating a company - """ - - # Check that different company types return different form titles - response = self.client.get(reverse('supplier-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Supplier') - - response = self.client.get(reverse('manufacturer-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Manufacturer') - - response = self.client.get(reverse('customer-create'), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertContains(response, 'Create new Customer') - - -class ManufacturerPartViewTests(CompanyViewTestBase): - """ - Tests for the ManufacturerPart views. - """ - - def test_manufacturer_part_create(self): - """ - Test the ManufacturerPartCreate view. - """ - - url = reverse('manufacturer-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many manufaturer parts are already in the database? - n = ManufacturerPart.objects.all().count() - - data = { - 'part': 1, - 'manufacturer': 6, - } - - # MPN is required! (form should fail) - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('MPN', None)) - - data['MPN'] = 'TEST-ME-123' - - (response, errors) = self.post(url, data, valid=True) - - # Check that the ManufacturerPart was created! - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) - - # Try to create duplicate ManufacturerPart - (response, errors) = self.post(url, data, valid=False) - - self.assertIsNotNone(errors.get('__all__', None)) - - # Check that the ManufacturerPart count stayed the same - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) - - def test_supplier_part_create(self): - """ - Test that the SupplierPartCreate view creates Manufacturer Part. - """ - - url = reverse('supplier-part-create') - - # First check that we can GET the form - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # How many manufacturer parts are already in the database? - n = ManufacturerPart.objects.all().count() - - data = { - 'part': 1, - 'supplier': 1, - 'SKU': 'SKU_TEST', - 'manufacturer': 6, - 'MPN': 'MPN_TEST', - } - - (response, errors) = self.post(url, data, valid=True) - - # Check that the ManufacturerPart was created! - self.assertEqual(n + 1, ManufacturerPart.objects.all().count()) - - def test_manufacturer_part_delete(self): - """ - Test the ManufacturerPartDelete view - """ - - url = reverse('manufacturer-part-delete') - - # Get form using 'part' argument - response = self.client.get(url, {'part': '2'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # POST to delete manufacturer part - n = ManufacturerPart.objects.count() - m = SupplierPart.objects.count() - - response = self.client.post( - url, - { - 'manufacturer-part-2': 'manufacturer-part-2', - 'confirm_delete': True - }, - HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(response.status_code, 200) - - # Check that the ManufacturerPart was deleted - self.assertEqual(n - 1, ManufacturerPart.objects.count()) - # Check that the SupplierParts were deleted - self.assertEqual(m - 2, SupplierPart.objects.count()) diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index e4a70b077a..79ffc34af5 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -192,18 +192,14 @@ class ManufacturerPartSimpleTest(TestCase): SKU='SKU_TEST', ) - kwargs = { - 'manufacturer': manufacturer.id, - 'MPN': 'MPN_TEST', - } - supplier_part.save(**kwargs) + supplier_part.save() def test_exists(self): - self.assertEqual(ManufacturerPart.objects.count(), 5) + self.assertEqual(ManufacturerPart.objects.count(), 4) # Check that manufacturer part was created from supplier part creation manufacturer_parts = ManufacturerPart.objects.filter(manufacturer=1) - self.assertEqual(manufacturer_parts.count(), 2) + self.assertEqual(manufacturer_parts.count(), 1) def test_delete(self): # Remove a part diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 51aa81f1c7..901e7f7089 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -8,20 +8,7 @@ from . import views company_detail_urls = [ - url(r'edit/?', views.CompanyEdit.as_view(), name='company-edit'), - url(r'delete/?', views.CompanyDelete.as_view(), name='company-delete'), - # url(r'orders/?', views.CompanyDetail.as_view(template_name='company/orders.html'), name='company-detail-orders'), - - url(r'^supplier-parts/', views.CompanyDetail.as_view(template_name='company/detail_supplier_part.html'), name='company-detail-supplier-parts'), - url(r'^manufacturer-parts/', views.CompanyDetail.as_view(template_name='company/detail_manufacturer_part.html'), name='company-detail-manufacturer-parts'), - url(r'^stock/', views.CompanyDetail.as_view(template_name='company/detail_stock.html'), name='company-detail-stock'), - url(r'^purchase-orders/', views.CompanyDetail.as_view(template_name='company/purchase_orders.html'), name='company-detail-purchase-orders'), - url(r'^assigned-stock/', views.CompanyDetail.as_view(template_name='company/assigned_stock.html'), name='company-detail-assigned-stock'), - url(r'^sales-orders/', views.CompanyDetail.as_view(template_name='company/sales_orders.html'), name='company-detail-sales-orders'), - url(r'^notes/', views.CompanyNotes.as_view(), name='company-notes'), - - url(r'^thumbnail/', views.CompanyImage.as_view(), name='company-image'), url(r'^thumb-download/', views.CompanyImageDownloadFromURL.as_view(), name='company-image-download'), # Any other URL @@ -31,11 +18,6 @@ company_detail_urls = [ company_urls = [ - url(r'new/supplier/', views.CompanyCreate.as_view(), name='supplier-create'), - url(r'new/manufacturer/', views.CompanyCreate.as_view(), name='manufacturer-create'), - url(r'new/customer/', views.CompanyCreate.as_view(), name='customer-create'), - url(r'new/?', views.CompanyCreate.as_view(), name='company-create'), - url(r'^(?P\d+)/', include(company_detail_urls)), url(r'suppliers/', views.CompanyIndex.as_view(), name='supplier-index'), @@ -46,49 +28,13 @@ company_urls = [ url(r'^.*$', views.CompanyIndex.as_view(), name='company-index'), ] -price_break_urls = [ - url('^new/', views.PriceBreakCreate.as_view(), name='price-break-create'), - - url(r'^(?P\d+)/edit/', views.PriceBreakEdit.as_view(), name='price-break-edit'), - url(r'^(?P\d+)/delete/', views.PriceBreakDelete.as_view(), name='price-break-delete'), -] - manufacturer_part_urls = [ - url(r'^new/?', views.ManufacturerPartCreate.as_view(), name='manufacturer-part-create'), - - url(r'^delete/', views.ManufacturerPartDelete.as_view(), name='manufacturer-part-delete'), - - # URLs for ManufacturerPartParameter views (create / edit / delete) - url(r'^parameter/', include([ - url(r'^new/', views.ManufacturerPartParameterCreate.as_view(), name='manufacturer-part-parameter-create'), - url(r'^(?P\d)/', include([ - url(r'^edit/', views.ManufacturerPartParameterEdit.as_view(), name='manufacturer-part-parameter-edit'), - url(r'^delete/', views.ManufacturerPartParameterDelete.as_view(), name='manufacturer-part-parameter-delete'), - ])), - ])), - + url(r'^(?P\d+)/', include([ - url(r'^edit/?', views.ManufacturerPartEdit.as_view(), name='manufacturer-part-edit'), - url(r'^suppliers/', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-suppliers'), - url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part_suppliers.html'), name='manufacturer-part-detail'), + url('^.*$', views.ManufacturerPartDetail.as_view(template_name='company/manufacturer_part.html'), name='manufacturer-part-detail'), ])), ] -supplier_part_detail_urls = [ - url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'), - - url(r'^manufacturers/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_manufacturers.html'), name='supplier-part-manufacturers'), - url(r'^pricing/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-pricing'), - url(r'^orders/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_orders.html'), name='supplier-part-orders'), - url(r'^stock/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_stock.html'), name='supplier-part-stock'), - - url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-detail'), -] - supplier_part_urls = [ - url(r'^new/?', views.SupplierPartCreate.as_view(), name='supplier-part-create'), - - url(r'delete/', views.SupplierPartDelete.as_view(), name='supplier-part-delete'), - - url(r'^(?P\d+)/', include(supplier_part_detail_urls)), + url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'), ] diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 74a583710a..f3a9af7628 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -7,39 +7,25 @@ Django views for interacting with Company app from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.urls import reverse -from django.forms import HiddenInput from django.core.files.base import ContentFile -from moneyed import CURRENCIES - from PIL import Image import requests import io -from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView -from InvenTree.helpers import str2bool +from InvenTree.views import AjaxUpdateView from InvenTree.views import InvenTreeRoleMixin -from .models import Company, ManufacturerPartParameter +from .models import Company from .models import ManufacturerPart from .models import SupplierPart -from .models import SupplierPriceBreak -from part.models import Part -from .forms import EditCompanyForm, EditManufacturerPartParameterForm -from .forms import CompanyImageForm -from .forms import EditManufacturerPartForm -from .forms import EditSupplierPartForm -from .forms import EditPriceBreakForm from .forms import CompanyImageDownloadForm -import common.models -import common.settings - class CompanyIndex(InvenTreeRoleMixin, ListView): """ View for displaying list of companies @@ -63,21 +49,18 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): 'title': _('Suppliers'), 'button_text': _('New Supplier'), 'filters': {'is_supplier': 'true'}, - 'create_url': reverse('supplier-create'), 'pagetype': 'suppliers', }, reverse('manufacturer-index'): { 'title': _('Manufacturers'), 'button_text': _('New Manufacturer'), 'filters': {'is_manufacturer': 'true'}, - 'create_url': reverse('manufacturer-create'), 'pagetype': 'manufacturers', }, reverse('customer-index'): { 'title': _('Customers'), 'button_text': _('New Customer'), 'filters': {'is_customer': 'true'}, - 'create_url': reverse('customer-create'), 'pagetype': 'customers', } } @@ -86,7 +69,6 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): 'title': _('Companies'), 'button_text': _('New Company'), 'filters': {}, - 'create_url': reverse('company-create'), 'pagetype': 'companies' } @@ -122,28 +104,6 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): return queryset -class CompanyNotes(UpdateView): - """ View for editing the 'notes' field of a Company object. - """ - - context_object_name = 'company' - template_name = 'company/notes.html' - model = Company - fields = ['notes'] - permission_required = 'company.view_company' - - def get_success_url(self): - return reverse('company-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', '')) - - return ctx - - class CompanyDetail(DetailView): """ Detail view for Company object """ context_obect_name = 'company' @@ -236,103 +196,6 @@ class CompanyImageDownloadFromURL(AjaxUpdateView): ) -class CompanyImage(AjaxUpdateView): - """ View for uploading an image for the Company """ - model = Company - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Update Company Image') - form_class = CompanyImageForm - permission_required = 'company.change_company' - - def get_data(self): - return { - 'success': _('Updated company image'), - } - - -class CompanyEdit(AjaxUpdateView): - """ View for editing a Company object """ - model = Company - form_class = EditCompanyForm - context_object_name = 'company' - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Company') - permission_required = 'company.change_company' - - def get_data(self): - return { - 'info': _('Edited company information'), - } - - -class CompanyCreate(AjaxCreateView): - """ View for creating a new Company object """ - model = Company - context_object_name = 'company' - form_class = EditCompanyForm - ajax_template_name = 'modal_form.html' - permission_required = 'company.add_company' - - def get_form_title(self): - - url = self.request.path - - if url == reverse('supplier-create'): - return _("Create new Supplier") - - if url == reverse('manufacturer-create'): - return _('Create new Manufacturer') - - if url == reverse('customer-create'): - return _('Create new Customer') - - return _('Create new Company') - - def get_initial(self): - """ Initial values for the form data """ - initials = super().get_initial().copy() - - url = self.request.path - - if url == reverse('supplier-create'): - initials['is_supplier'] = True - initials['is_customer'] = False - initials['is_manufacturer'] = False - - elif url == reverse('manufacturer-create'): - initials['is_manufacturer'] = True - initials['is_supplier'] = True - initials['is_customer'] = False - - elif url == reverse('customer-create'): - initials['is_customer'] = True - initials['is_manufacturer'] = False - initials['is_supplier'] = False - - return initials - - def get_data(self): - return { - 'success': _("Created new company"), - } - - -class CompanyDelete(AjaxDeleteView): - """ View for deleting a Company object """ - - model = Company - success_url = '/company/' - ajax_template_name = 'company/delete.html' - ajax_form_title = _('Delete Company') - context_object_name = 'company' - permission_required = 'company.delete_company' - - def get_data(self): - return { - 'danger': _('Company was deleted'), - } - - class ManufacturerPartDetail(DetailView): """ Detail view for ManufacturerPart """ model = ManufacturerPart @@ -347,223 +210,6 @@ class ManufacturerPartDetail(DetailView): return ctx -class ManufacturerPartEdit(AjaxUpdateView): - """ Update view for editing ManufacturerPart """ - - model = ManufacturerPart - context_object_name = 'part' - form_class = EditManufacturerPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Manufacturer Part') - - -class ManufacturerPartCreate(AjaxCreateView): - """ Create view for making new ManufacturerPart """ - - model = ManufacturerPart - form_class = EditManufacturerPartForm - ajax_template_name = 'company/manufacturer_part_create.html' - ajax_form_title = _('Create New Manufacturer Part') - context_object_name = 'part' - - def get_context_data(self): - """ - Supply context data to the form - """ - - ctx = super().get_context_data() - - # Add 'part' object - form = self.get_form() - - part = form['part'].value() - - try: - part = Part.objects.get(pk=part) - except (ValueError, Part.DoesNotExist): - part = None - - ctx['part'] = part - - return ctx - - def get_form(self): - """ Create Form instance to create a new ManufacturerPart object. - Hide some fields if they are not appropriate in context - """ - form = super(AjaxCreateView, self).get_form() - - if form.initial.get('part', None): - # Hide the part field - form.fields['part'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Provide initial data for new ManufacturerPart: - - - If 'manufacturer_id' provided, pre-fill manufacturer field - - If 'part_id' provided, pre-fill part field - """ - initials = super(ManufacturerPartCreate, self).get_initial().copy() - - manufacturer_id = self.get_param('manufacturer') - part_id = self.get_param('part') - - if manufacturer_id: - try: - initials['manufacturer'] = Company.objects.get(pk=manufacturer_id) - except (ValueError, Company.DoesNotExist): - pass - - if part_id: - try: - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - -class ManufacturerPartDelete(AjaxDeleteView): - """ Delete view for removing a ManufacturerPart. - - ManufacturerParts can be deleted using a variety of 'selectors'. - - - ?part= -> Delete a single ManufacturerPart object - - ?parts=[] -> Delete a list of ManufacturerPart objects - - """ - - success_url = '/manufacturer/' - ajax_template_name = 'company/manufacturer_part_delete.html' - ajax_form_title = _('Delete Manufacturer Part') - - role_required = 'purchase_order.delete' - - parts = [] - - def get_context_data(self): - ctx = {} - - ctx['parts'] = self.parts - - return ctx - - def get_parts(self): - """ Determine which ManufacturerPart object(s) the user wishes to delete. - """ - - self.parts = [] - - # User passes a single ManufacturerPart ID - if 'part' in self.request.GET: - try: - self.parts.append(ManufacturerPart.objects.get(pk=self.request.GET.get('part'))) - except (ValueError, ManufacturerPart.DoesNotExist): - pass - - elif 'parts[]' in self.request.GET: - - part_id_list = self.request.GET.getlist('parts[]') - - self.parts = ManufacturerPart.objects.filter(id__in=part_id_list) - - def get(self, request, *args, **kwargs): - self.request = request - self.get_parts() - - return self.renderJsonResponse(request, form=self.get_form()) - - def post(self, request, *args, **kwargs): - """ Handle the POST action for deleting ManufacturerPart object. - """ - - self.request = request - self.parts = [] - - for item in self.request.POST: - if item.startswith('manufacturer-part-'): - pk = item.replace('manufacturer-part-', '') - - try: - self.parts.append(ManufacturerPart.objects.get(pk=pk)) - except (ValueError, ManufacturerPart.DoesNotExist): - pass - - confirm = str2bool(self.request.POST.get('confirm_delete', False)) - - data = { - 'form_valid': confirm, - } - - if confirm: - for part in self.parts: - part.delete() - - return self.renderJsonResponse(self.request, data=data, form=self.get_form()) - - -class ManufacturerPartParameterCreate(AjaxCreateView): - """ - View for creating a new ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter - form_class = EditManufacturerPartParameterForm - ajax_form_title = _('Add Manufacturer Part Parameter') - - def get_form(self): - - form = super().get_form() - - # Hide the manufacturer_part field if specified - if form.initial.get('manufacturer_part', None): - form.fields['manufacturer_part'].widget = HiddenInput() - - return form - - def get_initial(self): - - initials = super().get_initial().copy() - - manufacturer_part = self.get_param('manufacturer_part') - - if manufacturer_part: - try: - initials['manufacturer_part'] = ManufacturerPartParameter.objects.get(pk=manufacturer_part) - except (ValueError, ManufacturerPartParameter.DoesNotExist): - pass - - return initials - - -class ManufacturerPartParameterEdit(AjaxUpdateView): - """ - View for editing a ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter - form_class = EditManufacturerPartParameterForm - ajax_form_title = _('Edit Manufacturer Part Parameter') - - def get_form(self): - - form = super().get_form() - - form.fields['manufacturer_part'].widget = HiddenInput() - - return form - - -class ManufacturerPartParameterDelete(AjaxDeleteView): - """ - View for deleting a ManufacturerPartParameter object - """ - - model = ManufacturerPartParameter - - class SupplierPartDetail(DetailView): """ Detail view for SupplierPart """ model = SupplierPart @@ -576,357 +222,3 @@ class SupplierPartDetail(DetailView): ctx = super().get_context_data(**kwargs) return ctx - - -class SupplierPartEdit(AjaxUpdateView): - """ Update view for editing SupplierPart """ - - model = SupplierPart - context_object_name = 'part' - form_class = EditSupplierPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Supplier Part') - - def save(self, supplier_part, form, **kwargs): - """ Process ManufacturerPart data """ - - manufacturer = form.cleaned_data.get('manufacturer', None) - MPN = form.cleaned_data.get('MPN', None) - kwargs = {'manufacturer': manufacturer, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - def get_form(self): - form = super().get_form() - - supplier_part = self.get_object() - - # Hide Manufacturer fields - form.fields['manufacturer'].widget = HiddenInput() - form.fields['MPN'].widget = HiddenInput() - - # It appears that hiding a MoneyField fails validation - # Therefore the idea to set the value before hiding - if form.is_valid(): - form.cleaned_data['single_pricing'] = supplier_part.unit_pricing - # Hide the single-pricing field (only for creating a new SupplierPart!) - form.fields['single_pricing'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Fetch data from ManufacturerPart """ - - initials = super(SupplierPartEdit, self).get_initial().copy() - - supplier_part = self.get_object() - - if supplier_part.manufacturer_part: - if supplier_part.manufacturer_part.manufacturer: - initials['manufacturer'] = supplier_part.manufacturer_part.manufacturer.id - initials['MPN'] = supplier_part.manufacturer_part.MPN - - return initials - - -class SupplierPartCreate(AjaxCreateView): - """ Create view for making new SupplierPart """ - - model = SupplierPart - form_class = EditSupplierPartForm - ajax_template_name = 'company/supplier_part_create.html' - ajax_form_title = _('Create new Supplier Part') - context_object_name = 'part' - - def validate(self, part, form): - - single_pricing = form.cleaned_data.get('single_pricing', None) - - if single_pricing: - # TODO - What validation steps can be performed on the single_pricing field? - pass - - def get_context_data(self): - """ - Supply context data to the form - """ - - ctx = super().get_context_data() - - # Add 'part' object - form = self.get_form() - - part = form['part'].value() - - try: - part = Part.objects.get(pk=part) - except (ValueError, Part.DoesNotExist): - part = None - - ctx['part'] = part - - return ctx - - def save(self, form): - """ - If single_pricing is defined, add a price break for quantity=1 - """ - - # Save the supplier part object - supplier_part = super().save(form) - - # Process manufacturer data - manufacturer = form.cleaned_data.get('manufacturer', None) - MPN = form.cleaned_data.get('MPN', None) - kwargs = {'manufacturer': manufacturer, - 'MPN': MPN, - } - supplier_part.save(**kwargs) - - single_pricing = form.cleaned_data.get('single_pricing', None) - - if single_pricing: - - supplier_part.add_price_break(1, single_pricing) - - return supplier_part - - def get_form(self): - """ Create Form instance to create a new SupplierPart object. - Hide some fields if they are not appropriate in context - """ - form = super(AjaxCreateView, self).get_form() - - if form.initial.get('part', None): - # Hide the part field - form.fields['part'].widget = HiddenInput() - - if form.initial.get('manufacturer', None): - # Hide the manufacturer field - form.fields['manufacturer'].widget = HiddenInput() - # Hide the MPN field - form.fields['MPN'].widget = HiddenInput() - - return form - - def get_initial(self): - """ Provide initial data for new SupplierPart: - - - If 'supplier_id' provided, pre-fill supplier field - - If 'part_id' provided, pre-fill part field - """ - initials = super(SupplierPartCreate, self).get_initial().copy() - - manufacturer_id = self.get_param('manufacturer') - supplier_id = self.get_param('supplier') - part_id = self.get_param('part') - manufacturer_part_id = self.get_param('manufacturer_part') - - supplier = None - - if supplier_id: - try: - supplier = Company.objects.get(pk=supplier_id) - initials['supplier'] = supplier - except (ValueError, Company.DoesNotExist): - supplier = None - - if manufacturer_id: - try: - initials['manufacturer'] = Company.objects.get(pk=manufacturer_id) - except (ValueError, Company.DoesNotExist): - pass - - if manufacturer_part_id: - try: - # Get ManufacturerPart instance information - manufacturer_part_obj = ManufacturerPart.objects.get(pk=manufacturer_part_id) - initials['part'] = Part.objects.get(pk=manufacturer_part_obj.part.id) - initials['manufacturer'] = manufacturer_part_obj.manufacturer.id - initials['MPN'] = manufacturer_part_obj.MPN - except (ValueError, ManufacturerPart.DoesNotExist, Part.DoesNotExist, Company.DoesNotExist): - pass - - if part_id: - try: - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - # Initial value for single pricing - if supplier: - currency_code = supplier.currency_code - else: - currency_code = common.settings.currency_code_default() - - currency = CURRENCIES.get(currency_code, None) - - if currency_code: - initials['single_pricing'] = ('', currency) - - return initials - - -class SupplierPartDelete(AjaxDeleteView): - """ Delete view for removing a SupplierPart. - - SupplierParts can be deleted using a variety of 'selectors'. - - - ?part= -> Delete a single SupplierPart object - - ?parts=[] -> Delete a list of SupplierPart objects - - """ - - success_url = '/supplier/' - ajax_template_name = 'company/supplier_part_delete.html' - ajax_form_title = _('Delete Supplier Part') - - role_required = 'purchase_order.delete' - - parts = [] - - def get_context_data(self): - ctx = {} - - ctx['parts'] = self.parts - - return ctx - - def get_parts(self): - """ Determine which SupplierPart object(s) the user wishes to delete. - """ - - self.parts = [] - - # User passes a single SupplierPart ID - if 'part' in self.request.GET: - try: - self.parts.append(SupplierPart.objects.get(pk=self.request.GET.get('part'))) - except (ValueError, SupplierPart.DoesNotExist): - pass - - elif 'parts[]' in self.request.GET: - - part_id_list = self.request.GET.getlist('parts[]') - - self.parts = SupplierPart.objects.filter(id__in=part_id_list) - - def get(self, request, *args, **kwargs): - self.request = request - self.get_parts() - - return self.renderJsonResponse(request, form=self.get_form()) - - def post(self, request, *args, **kwargs): - """ Handle the POST action for deleting supplier parts. - """ - - self.request = request - self.parts = [] - - for item in self.request.POST: - if item.startswith('supplier-part-'): - pk = item.replace('supplier-part-', '') - - try: - self.parts.append(SupplierPart.objects.get(pk=pk)) - except (ValueError, SupplierPart.DoesNotExist): - pass - - confirm = str2bool(self.request.POST.get('confirm_delete', False)) - - data = { - 'form_valid': confirm, - } - - if confirm: - for part in self.parts: - part.delete() - - return self.renderJsonResponse(self.request, data=data, form=self.get_form()) - - -class PriceBreakCreate(AjaxCreateView): - """ View for creating a supplier price break """ - - model = SupplierPriceBreak - form_class = EditPriceBreakForm - ajax_form_title = _('Add Price Break') - ajax_template_name = 'modal_form.html' - - def get_data(self): - return { - 'success': _('Added new price break') - } - - def get_part(self): - """ - Attempt to extract SupplierPart object from the supplied data. - """ - - try: - supplier_part = SupplierPart.objects.get(pk=self.request.GET.get('part')) - return supplier_part - except (ValueError, SupplierPart.DoesNotExist): - pass - - try: - supplier_part = SupplierPart.objects.get(pk=self.request.POST.get('part')) - return supplier_part - except (ValueError, SupplierPart.DoesNotExist): - pass - - return None - - def get_form(self): - - form = super(AjaxCreateView, self).get_form() - form.fields['part'].widget = HiddenInput() - - return form - - def get_initial(self): - - initials = super(AjaxCreateView, self).get_initial() - - supplier_part = self.get_part() - - initials['part'] = self.get_part() - - if supplier_part is not None: - currency_code = supplier_part.supplier.currency_code - else: - currency_code = common.settings.currency_code_default() - - # Extract the currency object associated with the code - currency = CURRENCIES.get(currency_code, None) - - if currency: - initials['price'] = [1.0, currency] - - return initials - - -class PriceBreakEdit(AjaxUpdateView): - """ View for editing a supplier price break """ - - model = SupplierPriceBreak - form_class = EditPriceBreakForm - ajax_form_title = _('Edit Price Break') - ajax_template_name = 'modal_form.html' - - def get_form(self): - - form = super(AjaxUpdateView, self).get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PriceBreakDelete(AjaxDeleteView): - """ View for deleting a supplier price break """ - - model = SupplierPriceBreak - ajax_form_title = _("Delete Price Break") - ajax_template_name = 'modal_delete_form.html' diff --git a/InvenTree/label/admin.py b/InvenTree/label/admin.py index 2e4967ffc2..8fee2b1f8f 100644 --- a/InvenTree/label/admin.py +++ b/InvenTree/label/admin.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals from django.contrib import admin -from .models import StockItemLabel, StockLocationLabel +from .models import StockItemLabel, StockLocationLabel, PartLabel class LabelAdmin(admin.ModelAdmin): @@ -13,3 +13,4 @@ class LabelAdmin(admin.ModelAdmin): admin.site.register(StockItemLabel, LabelAdmin) admin.site.register(StockLocationLabel, LabelAdmin) +admin.site.register(PartLabel, LabelAdmin) diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py index 8522857e30..b2d17efdfe 100644 --- a/InvenTree/label/api.py +++ b/InvenTree/label/api.py @@ -15,9 +15,10 @@ import InvenTree.helpers import common.models from stock.models import StockItem, StockLocation +from part.models import Part -from .models import StockItemLabel, StockLocationLabel -from .serializers import StockItemLabelSerializer, StockLocationLabelSerializer +from .models import StockItemLabel, StockLocationLabel, PartLabel +from .serializers import StockItemLabelSerializer, StockLocationLabelSerializer, PartLabelSerializer class LabelListView(generics.ListAPIView): @@ -132,6 +133,7 @@ class StockItemLabelMixin: for key in ['item', 'item[]', 'items', 'items[]']: if key in params: items = params.getlist(key, []) + break valid_ids = [] @@ -376,6 +378,112 @@ class StockLocationLabelPrint(generics.RetrieveAPIView, StockLocationLabelMixin, return self.print(request, locations) +class PartLabelMixin: + """ + Mixin for extracting Part objects from query parameters + """ + + def get_parts(self): + """ + Return a list of requested Part objects + """ + + parts = [] + + params = self.request.query_params + + for key in ['part', 'part[]', 'parts', 'parts[]']: + if key in params: + parts = params.getlist(key, []) + break + + valid_ids = [] + + for part in parts: + try: + valid_ids.append(int(part)) + except (ValueError): + pass + + # List of Part objects which match provided values + return Part.objects.filter(pk__in=valid_ids) + + +class PartLabelList(LabelListView, PartLabelMixin): + """ + API endpoint for viewing list of PartLabel objects + """ + + queryset = PartLabel.objects.all() + serializer_class = PartLabelSerializer + + def filter_queryset(self, queryset): + + queryset = super().filter_queryset(queryset) + + parts = self.get_parts() + + if len(parts) > 0: + + valid_label_ids = set() + + for label in queryset.all(): + + matches = True + + try: + filters = InvenTree.helpers.validateFilterString(label.filters) + except ValidationError: + continue + + for part in parts: + + part_query = Part.objects.filter(pk=part.pk) + + try: + if not part_query.filter(**filters).exists(): + matches = False + break + except FieldError: + matches = False + break + + if matches: + valid_label_ids.add(label.pk) + + # Reduce queryset to only valid matches + queryset = queryset.filter(pk__in=[pk for pk in valid_label_ids]) + + return queryset + + +class PartLabelDetail(generics.RetrieveUpdateDestroyAPIView): + """ + API endpoint for a single PartLabel object + """ + + queryset = PartLabel.objects.all() + serializer_class = PartLabelSerializer + + +class PartLabelPrint(generics.RetrieveAPIView, PartLabelMixin, LabelPrintMixin): + """ + API endpoint for printing a PartLabel object + """ + + queryset = PartLabel.objects.all() + serializer_class = PartLabelSerializer + + def get(self, request, *args, **kwargs): + """ + Check if valid part(s) have been provided + """ + + parts = self.get_parts() + + return self.print(request, parts) + + label_api_urls = [ # Stock item labels @@ -401,4 +509,16 @@ label_api_urls = [ # List view url(r'^.*$', StockLocationLabelList.as_view(), name='api-stocklocation-label-list'), ])), + + # Part labels + url(r'^part/', include([ + # Detail views + url(r'^(?P\d+)/', include([ + url(r'^print/', PartLabelPrint.as_view(), name='api-part-label-print'), + url(r'^.*$', PartLabelDetail.as_view(), name='api-part-label-detail'), + ])), + + # List view + url(r'^.*$', PartLabelList.as_view(), name='api-part-label-list'), + ])), ] diff --git a/InvenTree/label/apps.py b/InvenTree/label/apps.py index e51767d5f0..2556e11bca 100644 --- a/InvenTree/label/apps.py +++ b/InvenTree/label/apps.py @@ -37,6 +37,7 @@ class LabelConfig(AppConfig): if canAppAccessDatabase(): self.create_stock_item_labels() self.create_stock_location_labels() + self.create_part_labels() def create_stock_item_labels(self): """ @@ -65,7 +66,7 @@ class LabelConfig(AppConfig): ) if not os.path.exists(dst_dir): - logger.info(f"Creating missing directory: '{dst_dir}'") + logger.info(f"Creating required directory: '{dst_dir}'") os.makedirs(dst_dir, exist_ok=True) labels = [ @@ -109,24 +110,21 @@ class LabelConfig(AppConfig): logger.info(f"Copying label template '{dst_file}'") shutil.copyfile(src_file, dst_file) - try: - # Check if a label matching the template already exists - if StockItemLabel.objects.filter(label=filename).exists(): - continue + # Check if a label matching the template already exists + if StockItemLabel.objects.filter(label=filename).exists(): + continue - logger.info(f"Creating entry for StockItemLabel '{label['name']}'") + logger.info(f"Creating entry for StockItemLabel '{label['name']}'") - StockItemLabel.objects.create( - name=label['name'], - description=label['description'], - label=filename, - filters='', - enabled=True, - width=label['width'], - height=label['height'], - ) - except: - pass + StockItemLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True, + width=label['width'], + height=label['height'], + ) def create_stock_location_labels(self): """ @@ -155,7 +153,7 @@ class LabelConfig(AppConfig): ) if not os.path.exists(dst_dir): - logger.info(f"Creating missing directory: '{dst_dir}'") + logger.info(f"Creating required directory: '{dst_dir}'") os.makedirs(dst_dir, exist_ok=True) labels = [ @@ -206,21 +204,103 @@ class LabelConfig(AppConfig): logger.info(f"Copying label template '{dst_file}'") shutil.copyfile(src_file, dst_file) - try: - # Check if a label matching the template already exists - if StockLocationLabel.objects.filter(label=filename).exists(): - continue + # Check if a label matching the template already exists + if StockLocationLabel.objects.filter(label=filename).exists(): + continue - logger.info(f"Creating entry for StockLocationLabel '{label['name']}'") + logger.info(f"Creating entry for StockLocationLabel '{label['name']}'") - StockLocationLabel.objects.create( - name=label['name'], - description=label['description'], - label=filename, - filters='', - enabled=True, - width=label['width'], - height=label['height'], - ) - except: - pass + StockLocationLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True, + width=label['width'], + height=label['height'], + ) + + def create_part_labels(self): + """ + Create database entries for the default PartLabel templates, + if they do not already exist. + """ + + try: + from .models import PartLabel + except: + # Database might not yet be ready + return + + src_dir = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'templates', + 'label', + 'part', + ) + + dst_dir = os.path.join( + settings.MEDIA_ROOT, + 'label', + 'inventree', + 'part', + ) + + if not os.path.exists(dst_dir): + logger.info(f"Creating required directory: '{dst_dir}'") + os.makedirs(dst_dir, exist_ok=True) + + labels = [ + { + 'file': 'part_label.html', + 'name': 'Part Label', + 'description': 'Simple part label', + 'width': 70, + 'height': 24, + }, + ] + + for label in labels: + + filename = os.path.join( + 'label', + 'inventree', + 'part', + label['file'] + ) + + src_file = os.path.join(src_dir, label['file']) + dst_file = os.path.join(settings.MEDIA_ROOT, filename) + + to_copy = False + + if os.path.exists(dst_file): + # File already exists - let's see if it is the "same" + + if not hashFile(dst_file) == hashFile(src_file): + logger.info(f"Hash differs for '{filename}'") + to_copy = True + + else: + logger.info(f"Label template '{filename}' is not present") + to_copy = True + + if to_copy: + logger.info(f"Copying label template '{dst_file}'") + shutil.copyfile(src_file, dst_file) + + # Check if a label matching the template already exists + if PartLabel.objects.filter(label=filename).exists(): + continue + + logger.info(f"Creating entry for PartLabel '{label['name']}'") + + PartLabel.objects.create( + name=label['name'], + description=label['description'], + label=filename, + filters='', + enabled=True, + width=label['width'], + height=label['height'], + ) diff --git a/InvenTree/label/migrations/0008_auto_20210708_2106.py b/InvenTree/label/migrations/0008_auto_20210708_2106.py new file mode 100644 index 0000000000..ea57526909 --- /dev/null +++ b/InvenTree/label/migrations/0008_auto_20210708_2106.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.4 on 2021-07-08 11:06 + +import django.core.validators +from django.db import migrations, models +import label.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('label', '0007_auto_20210513_1327'), + ] + + operations = [ + migrations.CreateModel( + name='PartLabel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Label name', max_length=100, verbose_name='Name')), + ('description', models.CharField(blank=True, help_text='Label description', max_length=250, null=True, verbose_name='Description')), + ('label', models.FileField(help_text='Label template file', unique=True, upload_to=label.models.rename_label, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html'])], verbose_name='Label')), + ('enabled', models.BooleanField(default=True, help_text='Label template is enabled', verbose_name='Enabled')), + ('width', models.FloatField(default=50, help_text='Label width, specified in mm', validators=[django.core.validators.MinValueValidator(2)], verbose_name='Width [mm]')), + ('height', models.FloatField(default=20, help_text='Label height, specified in mm', validators=[django.core.validators.MinValueValidator(2)], verbose_name='Height [mm]')), + ('filename_pattern', models.CharField(default='label.pdf', help_text='Pattern for generating label filenames', max_length=100, verbose_name='Filename Pattern')), + ('filters', models.CharField(blank=True, help_text='Part query filters (comma-separated value of key=value pairs)', max_length=250, validators=[label.models.validate_part_filters], verbose_name='Filters')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='stockitemlabel', + name='filters', + field=models.CharField(blank=True, help_text='Query filters (comma-separated list of key=value pairs),', max_length=250, validators=[label.models.validate_stock_item_filters], verbose_name='Filters'), + ), + ] diff --git a/InvenTree/label/models.py b/InvenTree/label/models.py index a5d8314193..b558f10e73 100644 --- a/InvenTree/label/models.py +++ b/InvenTree/label/models.py @@ -12,6 +12,7 @@ import datetime from django.conf import settings from django.db import models +from django.urls import reverse from django.core.validators import FileExtensionValidator, MinValueValidator from django.core.exceptions import ValidationError, FieldError @@ -24,6 +25,8 @@ from InvenTree.helpers import validateFilterString, normalize import common.models import stock.models +import part.models + try: from django_weasyprint import WeasyTemplateResponseMixin @@ -58,6 +61,13 @@ def validate_stock_location_filters(filters): return filters +def validate_part_filters(filters): + + filters = validateFilterString(filters, model=part.models.Part) + + return filters + + class WeasyprintLabelMixin(WeasyTemplateResponseMixin): """ Class for rendering a label to a PDF @@ -237,14 +247,19 @@ class StockItemLabel(LabelTemplate): Template for printing StockItem labels """ + @staticmethod + def get_api_url(): + return reverse('api-stockitem-label-list') + SUBDIR = "stockitem" filters = models.CharField( blank=True, max_length=250, - help_text=_('Query filters (comma-separated list of key=value pairs'), + help_text=_('Query filters (comma-separated list of key=value pairs),'), verbose_name=_('Filters'), validators=[ - validate_stock_item_filters] + validate_stock_item_filters + ] ) def matches_stock_item(self, item): @@ -290,6 +305,10 @@ class StockLocationLabel(LabelTemplate): Template for printing StockLocation labels """ + @staticmethod + def get_api_url(): + return reverse('api-stocklocation-label-list') + SUBDIR = "stocklocation" filters = models.CharField( @@ -326,3 +345,57 @@ class StockLocationLabel(LabelTemplate): 'location': location, 'qr_data': location.format_barcode(brief=True), } + + +class PartLabel(LabelTemplate): + """ + Template for printing Part labels + """ + + @staticmethod + def get_api_url(): + return reverse('api-part-label-list') + + SUBDIR = 'part' + + filters = models.CharField( + blank=True, max_length=250, + help_text=_('Part query filters (comma-separated value of key=value pairs)'), + verbose_name=_('Filters'), + validators=[ + validate_part_filters + ] + ) + + def matches_part(self, part): + """ + Test if this label template matches a given Part object + """ + + try: + filters = validateFilterString(self.filters) + parts = part.models.Part.objects.filter(**filters) + except (ValidationError, FieldError): + return False + + parts = parts.filter(pk=part.pk) + + return parts.exists() + + def get_context_data(self, request): + """ + Generate context data for each provided Part object + """ + + part = self.object_to_print + + return { + 'part': part, + 'category': part.category, + 'name': part.name, + 'description': part.description, + 'IPN': part.IPN, + 'revision': part.revision, + 'qr_data': part.format_barcode(brief=True), + 'qr_url': part.format_barcode(url=True, request=request), + } diff --git a/InvenTree/label/serializers.py b/InvenTree/label/serializers.py index c9d487af23..47ccd51ba1 100644 --- a/InvenTree/label/serializers.py +++ b/InvenTree/label/serializers.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals from InvenTree.serializers import InvenTreeModelSerializer from InvenTree.serializers import InvenTreeAttachmentSerializerField -from .models import StockItemLabel, StockLocationLabel +from .models import StockItemLabel, StockLocationLabel, PartLabel class StockItemLabelSerializer(InvenTreeModelSerializer): @@ -43,3 +43,22 @@ class StockLocationLabelSerializer(InvenTreeModelSerializer): 'filters', 'enabled', ] + + +class PartLabelSerializer(InvenTreeModelSerializer): + """ + Serializes a PartLabel object + """ + + label = InvenTreeAttachmentSerializerField(required=True) + + class Meta: + model = PartLabel + fields = [ + 'pk', + 'name', + 'description', + 'label', + 'filters', + 'enabled', + ] diff --git a/InvenTree/label/templates/label/part/part_label.html b/InvenTree/label/templates/label/part/part_label.html new file mode 100644 index 0000000000..558e1bca5b --- /dev/null +++ b/InvenTree/label/templates/label/part/part_label.html @@ -0,0 +1,33 @@ +{% extends "label/label_base.html" %} + +{% load barcode %} + +{% block style %} + +.qr { + position: fixed; + left: 0mm; + top: 0mm; + height: {{ height }}mm; + width: {{ height }}mm; +} + +.part { + font-family: Arial, Helvetica, sans-serif; + display: inline; + position: absolute; + left: {{ height }}mm; + top: 2mm; +} + +{% endblock %} + +{% block content %} + + + +
                + {{ part.full_name }} +
                + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 9eeedee291..6d43eccbe6 100644 --- a/InvenTree/locale/de/LC_MESSAGES/django.po +++ b/InvenTree/locale/de/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: German\n" "Language: de_DE\n" @@ -29,14 +29,14 @@ msgstr "Keine Aktion angegeben" msgid "No matching action found" msgstr "Keine passende Aktion gefunden" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "Datum eingeben" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Bestätigen" @@ -72,134 +72,143 @@ msgstr "Thema anwenden" msgid "Select Category" msgstr "Kategorie auswählen" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Doppelte Seriennummer: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "Keine gültige Menge" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "Keine Seriennummer angegeben" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "Ungültige Gruppe: {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "Doppelte Seriennummer: {g}" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "Keine Seriennummern gefunden" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "Anzahl der eindeutigen Seriennummern ({s}) muss mit der Anzahl ({q}) übereinstimmen" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "Anhang" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "Datei zum Anhängen auswählen" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Kommentar" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "Datei-Kommentar" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Benutzer" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "Hochladedatum" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Name" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Beschreibung" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "Beschreibung (optional)" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "Eltern" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "Englisch" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Französisch" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Deutsch" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Polnisch" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Türkisch" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Hintergrund-Prozess-Kontrolle fehlgeschlagen" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "E-Mail-Backend nicht konfiguriert" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "InvenTree Status-Überprüfung fehlgeschlagen" @@ -372,27 +381,27 @@ msgstr "Überschuss darf 100% nicht überschreiten" msgid "Overage must be an integer value or a percentage" msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Element löschen" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Häkchen setzen um Löschung von Objekt zu bestätigen" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Benutzerinformationen bearbeiten" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Passwort eingeben" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Passwörter stimmen nicht überein" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Systeminformationen" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "geplantes Bestelldatum" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "Zieldatum" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "Zieldatum für Bauauftrag-Fertigstellung." -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "Anzahl" @@ -500,7 +507,7 @@ msgstr "Anzahl der zu bauenden Teile" msgid "Enter quantity for build output" msgstr "Menge der Endprodukte angeben" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "Seriennummer" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "Bauauftrag als vollständig markieren" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "Lagerort" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "Lagerort der Endprodukte" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "Status" @@ -581,286 +588,284 @@ msgstr "Bauabbruch bestätigen" msgid "Select quantity of stock to allocate" msgstr "Menge der BestandsObjekte für Zuordnung auswählen" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Bauauftrag" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "Bauaufträge" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "Bauauftragsreferenz" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "Referenz" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "Kurze Beschreibung des Baus" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "Eltern-Bauauftrag" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "Bauauftrag, zu dem dieser Bauauftrag zugwiesen ist" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "Teil" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "Teil für den Bauauftrag wählen" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "Auftrag Referenz" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "Bestellung, die diesem Bauauftrag zugewiesen ist" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "Quell-Lagerort" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "Entnahme-Lagerort für diesen Bauauftrag wählen (oder leer lassen für einen beliebigen Lagerort)" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "Ziel-Lagerort" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "Lagerort an dem fertige Objekte gelagert werden auswählen" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "Bau-Anzahl" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "Anzahl der zu bauenden BestandsObjekt" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "Fertiggestellte Teile" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "Anzahl der fertigen BestandsObjekte" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "Bauauftrags-Status" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "Bau-Statuscode" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "Losnummer" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "Losnummer für dieses Endprodukt" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "Erstelldatum" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "geplantes Fertigstellungsdatum" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "Fertigstellungsdatum" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "Fertiggestellt von" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "Aufgegeben von" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "Nutzer der diesen Bauauftrag erstellt hat" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Verantwortlicher Benutzer" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "Nutzer der für diesen Bauauftrag zuständig ist" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "Externer Link" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "Link zu einer externen URL" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "Notizen" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "Extranotizen für den Bauauftrag" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "kein Endprodukt angegeben" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "Endprodukt bereits hergstellt" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "Endprodukt stimmt nicht mit dem Bauauftrag überein" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "Bauauftrags-Objekt muss für Bauauftrag, Lager-Objekt und installiert_in eindeutig sein" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "Bauauftragsposition muss ein Endprodukt festlegen, da der übergeordnete Teil verfolgbar ist" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "Reserviermenge ({n}) muss kleiner Bestandsmenge ({q}) sein. Zugewiesene Anzahl ({n}) darf nicht die verfügbare ({q}) Anzahl überschreiten" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "Zu viele BestandsObjekt zugewiesen" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "Reserviermenge muss größer null sein" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "Anzahl muss 1 für Objekte mit Seriennummer sein" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "Ausgewähltes BestandsObjekt nicht Stückliste für Teil '{p}' gefunden" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "Bauauftrag" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "Bauauftrag starten um Teile zuzuweisen" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "BestandsObjekt" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "Quell-BestandsObjekt" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "BestandsObjekt-Anzahl dem Bauauftrag zuweisen" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "Installiere in" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "Ziel-BestandsObjekt" @@ -880,7 +885,7 @@ msgstr "Lagerbestand Bauauftrag zuweisen" msgid "Auto Allocate" msgstr "Automatisch zuweisen" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "Bestandszuordnung aufheben" @@ -894,8 +899,8 @@ msgstr "Benötigte Teile bestellen" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "Teile bestellen" @@ -913,23 +918,52 @@ msgstr "Dieser Bauauftrag hat keine zugeordneten Stücklisten-Einträge" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "Seriennummer" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Anhänge" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "Anhang hinzufügen" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "Anhang bearbeiten" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "Anhang löschen" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "Lagerbestand automatisch zuweisen" @@ -978,7 +1012,7 @@ msgstr "Lagerbestand wurde Bauauftrag noch nicht vollständig zugewiesen" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "Admin" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "Überfällig" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "Fortschritt" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "Auftrag" @@ -1185,7 +1218,10 @@ msgstr "Ausgangs-Lager" msgid "Stock can be taken from any available location." msgstr "Bestand kann jedem verfügbaren Lagerort entnommen werden." -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "Ziel-Lager" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "Ziel-Lagerort nicht angegeben" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Losnummer" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "Erstellt" @@ -1210,7 +1246,7 @@ msgstr "Erstellt" msgid "No target date set" msgstr "Kein Ziel-Datum gesetzt" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "Fertig" @@ -1248,9 +1284,9 @@ msgstr "Bauauftrag-details" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "Details" @@ -1285,8 +1321,7 @@ msgstr "Bermerkungen bearbeiten" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Speichern" @@ -1315,7 +1350,7 @@ msgstr "Endprodukt anlegen" msgid "Maximum output quantity is " msgstr "Maximale Endproduktmenge ist " -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "Seriennummern existieren bereits" @@ -1331,7 +1366,7 @@ msgstr "Endprodukt entfernen" msgid "Confirm unallocation of build stock" msgstr "Entfernung von Bestands-Zuordnung bestätigen" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "Bestätigungsbox bestätigen" @@ -1411,8 +1446,8 @@ msgstr "Teil muss aktuell im Bestand sein" msgid "Stock item is over-allocated" msgstr "BestandObjekt ist zu oft zugewiesen" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "Verfügbar" @@ -1428,60 +1463,35 @@ msgstr "Bestandszuordnung bearbeiten" msgid "Updated Build Item" msgstr "Bauobjekt aktualisiert" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "Bauauftrags-Anhang hinzufügen" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "Anhang hinzugefügt" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "Anhang bearbeiten" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "Anhang aktualisiert" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "Anhang löschen" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "Anhang gelöscht" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "Dateiformat nicht unterstützt: {ext.upper()}" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "Fehler beim Lesen der Datei (ungültiges Format)" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "Fehler beim Lesen der Datei (falsche Größe)" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "Fehler beim Lesen der Datei (Daten könnten beschädigt sein)" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "Datei" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "Datei zum Hochladen auswählen" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "{name.title()} Datei" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "{name} Datei zum Hochladen auswählen" @@ -1502,7 +1512,7 @@ msgstr "Name der Instanz verwenden" msgid "Use the instance name in the title-bar" msgstr "Den Namen der Instanz in der Titelleiste verwenden" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "Firmenname" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "Basis-URL für dieses Instanz" #: common/models.py:85 +msgid "Default Currency" +msgstr "" + +#: common/models.py:86 +msgid "Default currency" +msgstr "" + +#: common/models.py:92 msgid "Download from URL" msgstr "Von URL herunterladen" -#: common/models.py:86 +#: common/models.py:93 msgid "Allow download of remote images and files from external URL" msgstr "Herunterladen von externen Bildern und Dateien von URLs erlaubt" -#: common/models.py:92 +#: common/models.py:99 msgid "Barcode Support" msgstr "Bacode-Feature verwenden" -#: common/models.py:93 +#: common/models.py:100 msgid "Enable barcode scanner support" msgstr "Barcode-Scanner Unterstützung" -#: common/models.py:99 +#: common/models.py:106 msgid "IPN Regex" msgstr "IPN Regex" -#: common/models.py:100 +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "RegEx Muster für die Zuordnung von Teil-IPN" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "Mehrere Artikel mit gleicher IPN erlaubt" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "Mehrere Artikel mit gleicher IPN erlaubt" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "Ändern von IPN erlaubt" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "Ändern der IPN während des Bearbeiten eines Teils erlaubt" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "Teil-Stückliste kopieren" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "Stückliste von Teil kopieren wenn das Teil dupliziert wird " -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "Teil-Parameter kopieren" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "Parameter-Daten für dieses Teil kopieren wenn das Teil dupliziert wird" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "Teil-Testdaten kopieren" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "Test-Daten für dieses Teil kopieren wenn das Teil dupliziert wird" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "Kategorie-Parametervorlage kopieren" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "Kategorie-Parameter Vorlagen kopieren wenn ein Teil angelegt wird" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "Aktuelle Teile-Stände" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "Anzahl der neusten Teile auf der Startseite" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "Vorlage" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "Teile sind standardmäßig Vorlagen" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "Baugruppe" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "Teile können standardmäßig aus anderen Teilen angefertigt werden" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "Komponente" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "Teile können standardmäßig in Baugruppen benutzt werden" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "Kaufbar" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "Artikel sind grundsätzlich kaufbar" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "Verkäuflich" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "Artikel sind grundsätzlich verkaufbar" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "Nachverfolgbar" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "Artikel sind grundsätzlich verfolgbar" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "Virtuell" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "Teile sind grundsätzlich virtuell" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "zeige Bestand in Eingabemasken" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "Zeige den verfügbaren Bestand in einigen Eingabemasken" -#: common/models.py:209 templates/stats.html:25 +#: common/models.py:216 +msgid "Show Import in Views" +msgstr "" + +#: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 msgid "Debug Mode" msgstr "Entwickler-Modus" -#: common/models.py:210 +#: common/models.py:252 msgid "Generate reports in debug mode (HTML output)" msgstr "Berichte im Entwickler-Modus generieren (als HTML)" -#: common/models.py:216 +#: common/models.py:258 msgid "Page Size" msgstr "Seitengröße" -#: common/models.py:217 +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "Standardseitenformat für PDF-Bericht" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "Test-Berichte" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "Erstellung von Test-Berichten aktivieren" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "Bestands-Ablauf" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "Ablaufen von Bestand ermöglichen" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "Abgelaufenen Bestand verkaufen" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "Verkauf von abgelaufenem Bestand erlaubt" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "Bestands-Stehzeit" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "Anzahl an Tagen, an denen Bestand als abgestanden markiert wird, bevor sie ablaufen" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "Tage" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "Abgelaufenen Bestand verbauen" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "Verbauen von abgelaufenen Bestand erlaubt" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "Bestands-Eigentümerkontrolle" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "Eigentümerkontrolle für Lagerorte und Teile aktivieren" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "Gruppieren nach Teil" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "Bestand in Tabellen anhand von Teil-Referenz gruppieren" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "aktueller Bestand" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "Anzahl des geänderten Bestands auf der Startseite" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "Bauauftrag-Referenz Präfix" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "Präfix für Bauauftrag-Referenz" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "Bauauftrag-Referenz RegEx" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "RegEx Muster für die Zuordnung von Bauauftrag-Referenzen" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "Auftrags-Referenz Präfix" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "Präfix für Auftrags-Referenz" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "Bestellungs-Referenz Präfix" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "Präfix für Bestellungs-Referenz" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "Einstellungs-Schlüssel (muss einzigartig sein, Groß-/ Kleinschreibung wird nicht beachtet)" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "Einstellungs-Wert" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "Nur Ganzzahl eingeben" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "Wahrheitswert erforderlich" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "Nur Ganzzahl eingeben" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "Schlüsseltext muss eindeutig sein" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "Preisstaffelungs Anzahl" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "Preis" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "Stückpreis für die angegebene Anzahl" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "Standard" @@ -1830,25 +1888,30 @@ msgstr "Standard" msgid "Current value" msgstr "Aktueller Wert" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "Einstellungen ändern" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "Angegebener Wert nicht erlaubt" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "Angegebener Wert muss ein Wahrheitswert sein" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "Datei hochgeladen" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "Übereinstimmende Felder" @@ -1856,257 +1919,303 @@ msgstr "Übereinstimmende Felder" msgid "Match Items" msgstr "Positionen zuordnen" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "Felder zuteilen fehlgeschlagen" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" -msgstr "Währung" +#: common/views.py:586 +msgid "Parts imported" +msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" -msgstr "Standard-Währung für diese Firma" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" +msgstr "Vorheriger Schritt" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "URL" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "Bild-URL" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "Einzelpreis" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "Preis für eine Einheit" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "Hersteller auswählen" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "Hersteller-Teilenummer" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "MPN" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "Firmenbeschreibung" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "Firmenbeschreibung" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "Website" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "Firmenwebsite Adresse/URL" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "Adresse" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "Firmenadresse" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "Kontakt-Tel." -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "Kontakt-Telefon" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "Email" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "Kontakt-Email" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "Kontakt" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "Anlaufstelle" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "Link" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "Link auf externe Firmeninformation" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "Bild" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "ist Kunde" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "Verkaufen Sie Teile an diese Firma?" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "ist Zulieferer" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "Kaufen Sie Teile von dieser Firma?" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "ist Hersteller" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "Produziert diese Firma Teile?" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "Währung" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "Standard-Währung für diese Firma" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "Basisteil" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "Teil auswählen" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "Hersteller" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "Externe URL für das Herstellerteil" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "Teilbeschreibung des Herstellers" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "Herstellerteil" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "Wert" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "Einheiten" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "Zulieferer" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "Zulieferer auswählen" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "SKU (Lagerbestandseinheit)" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "Lagerbestandseinheit (SKU) des Zulieferers" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "Herstellerteil" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "Herstellerteil auswählen" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "Teil-URL des Zulieferers" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "Zuliefererbeschreibung des Teils" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Notiz" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "Basiskosten" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "Mindestpreis" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "Verpackungen" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "Teile-Verpackungen" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "Vielfache" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "Mehrere bestellen" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "Zugeordneter Bestand" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "Firma" @@ -2120,7 +2229,7 @@ msgstr "Neues Bild hochladen" msgid "Download image from URL" msgstr "Bild von URL herunterladen" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "Bestellung anlegen" @@ -2128,7 +2237,8 @@ msgstr "Bestellung anlegen" msgid "Edit company information" msgstr "Firmeninformation bearbeiten" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "Firma löschen" @@ -2142,17 +2252,10 @@ msgstr "Firmendetails" msgid "Phone" msgstr "Telefon" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "Sind Sie sicher, dass Sie die Firma '%(name)s' löschen wollen?" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." -msgstr "Es gibt %(count)s Teile, die von diesem Unternehmen bezogen werden.
                \n" -"Wenn dieser Lieferant gelöscht wird, werden auch diese Zulieferer-Teile gelöscht." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" +msgstr "" #: company/templates/company/detail.html:21 msgid "Company Name" @@ -2166,11 +2269,11 @@ msgstr "Keine Website angegeben" msgid "Uses default currency" msgstr "verwendet Standard-Währung" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "Kunde" @@ -2191,7 +2294,8 @@ msgstr "Neues Herstellerteil" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2199,7 +2303,7 @@ msgstr "Optionen" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "Teile bestellen" @@ -2213,26 +2317,25 @@ msgstr "Teile löschen" msgid "Delete Parts" msgstr "Teile löschen" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "Neues Teil" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "Neues Teil hinzufügen" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "Neuer Hersteller" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "Neuen Hersteller anlegen" @@ -2242,40 +2345,37 @@ msgstr "Zulieferer-Bestand" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "Exportieren" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "Zuliefererteile" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "Neues Zuliefererteil anlegen" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "Neues Zuliefererteil" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "Neuer Zulieferer" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "Neuen Zulieferer anlegen" @@ -2310,19 +2410,19 @@ msgstr "Herstellerteil-Details" msgid "Internal Part" msgstr "Internes Teil" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" -msgstr "Sind Sie sicher, dass sie die folgenden Herstellerteile löschen möchten?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" +msgstr "Herstellerteil ändern" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" -msgstr "Für dieses Herstellerteil sind %(count)s Lieferanten definiert. Wenn Sie es löschen, werden die folgenden Lieferantenteile ebenfalls gelöscht:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" +msgstr "Herstellerteil löschen" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "Zulieferer" @@ -2333,13 +2433,13 @@ msgstr "Herstellerteil-Bestand" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "Lagerbestand" @@ -2359,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "Zuliefererteil entfernen" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "Löschen" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "Parameter" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "Neuer Parameter" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "Neuen Zulieferer anlegen" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2380,14 +2512,14 @@ msgstr "Hergestellte Teile" msgid "Supplied Parts" msgstr "Zuliefererteile" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "Teilbestand" @@ -2397,11 +2529,11 @@ msgstr "Teilbestand" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "Aufträge" @@ -2409,11 +2541,11 @@ msgstr "Aufträge" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "Bestellungen" @@ -2442,8 +2574,9 @@ msgid "New Sales Order" msgstr "Neuer Auftrag" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "Zuliefererteil" @@ -2488,449 +2621,401 @@ msgid "Order Part" msgstr "Teil bestellen" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "Preisinformationen ansehen" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "Preisstaffel hinzufügen" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "Keine Informationen zur Preisstaffel gefunden" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "Preisstaffel löschen" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "Preisstaffel bearbeiten" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "Preisstaffel bearbeiten" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "Preisstaffel löschen" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "Hersteller" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "Kunden" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "Neuer Kunde" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "Firmen" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "Neue Firma" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "Bild herunterladen" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "Bildgröße überschreitet maximal-erlaubte Größe für Downloads" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "Ungültige Antwort {code}" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "Angegebene URL ist kein gültiges Bild" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "Firmenbild aktualisieren" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "Aktualisiertes Firmenbild" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "Firma bearbeiten" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "Firmeninformation bearbeitet" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "Neuen Kunden anlegen" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "Neue Firma anlegen" - -#: company/views.py:316 -msgid "Created new company" -msgstr "Neue Firma angelegt" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "Firma gelöscht" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "Herstellerteil ändern" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "Neues Herstellerteil anlegen" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "Herstellerteil löschen" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "Zuliefererteil bearbeiten" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "Neues Zuliefererteil anlegen" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "Zuliefererteil entfernen" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "neue Preisstaffel hinzufügt" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "Preisstaffel bearbeiten" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "Preisstaffel löschen" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "Keine korrekten Objekte für Vorlage gegeben" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "Label Name" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "Label Beschreibung" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "Label" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "Label-Vorlage-Datei" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "Aktiviert" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "Label-Vorlage ist aktiviert" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "Breite [mm]" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "Label-Breite in mm" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "Höhe [mm]" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "Label-Höhe in mm" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "Dateinamen-Muster" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "Muster für die Erstellung von Label-Dateinamen" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "Filter" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "Bestellung aufgeben" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "Bestellung als vollständig markieren" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "Bestellung stornieren" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "Bestellung versenden" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "Teile in diesen Lagerort empfangen" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "Bestellungs-Referenz" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "Zieldatum für Auftrags-Lieferung." - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "Auftrag-Nummer eingeben" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "Zieldatum für Auftrags-Fertigstellung." - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "Seriennummern für BestandsObjekt eingeben" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "Menge der BestandsObjekt eingeben" -#: order/models.py:101 -msgid "Order reference" -msgstr "Bestell-Referenz" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "Bestellungs-Beschreibung" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "Link auf externe Seite" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "Erstellt von" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "Nutzer oder Gruppe der/die für diesen Auftrag zuständig ist/sind" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "Bestell-Notizen" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "Bestell-Referenz" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "Bestellungs-Status" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "Firma bei der die Teile bestellt werden" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "Zulieferer-Referenz" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "Zulieferer Bestellreferenz" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "Empfangen von" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "Aufgabedatum" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "Datum an dem die Bestellung aufgegeben wurde" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "Ziel-Versanddatum" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "Geplantes Lieferdatum für Auftrag." -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "Datum an dem der Auftrag fertigstellt wurde" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "Teile-Zulieferer muss dem Zulieferer der Bestellung entsprechen" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "Nur Teile aufgegebener Bestllungen können empfangen werden" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "Anzahl muss eine positive Zahl sein" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "Firma an die die Teile verkauft werden" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "Kundenreferenz" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "Bestellreferenz" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "Zieldatum für Auftrags-Fertigstellung." + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "Versanddatum" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "Versand von" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "Bestellung kann nicht versendet werden weil er nicht anhängig ist" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "Anzahl" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "Position - Referenz" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "Bestellung" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "Bestellung" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "Zuliefererteil" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "Empfangen" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "Preis" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "Preis pro Einheit" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "Wo möchte der Käufer diesen Artikel gelagert haben?" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "Verkaufspreis" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "Stückverkaufspreis" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "BestandsObjekt wurde nicht zugewiesen" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "Kann BestandsObjekt keiner Zeile mit einem anderen Teil hinzufügen" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "Kann BestandsObjekt keiner Zeile ohne Teil hinzufügen" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "Die zugeordnete Anzahl darf nicht die verfügbare Anzahl überschreiten" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "Anzahl für BestandsObjekt mit Seriennummer muss 1 sein" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "Position" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "Position" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "BestandsObjekt für Zuordnung auswählen" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "Anzahl für Bestandszuordnung eingeben" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2956,7 +3041,7 @@ msgid "Export order to file" msgstr "Exportiere Bestellung in Datei" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "Bestellungs-Details" @@ -2975,16 +3060,22 @@ msgstr "Bestellstatus" msgid "Issued" msgstr "Aufgegeben" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "Bestellung bearbeiten" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "Neuer Lagerort" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "Neuen Lagerort anlegen" @@ -3015,57 +3106,71 @@ msgstr "Notizen zur Bestellung" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "Es fehlt eine Auswahl für die folgende benötigte Spalte" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "Doppelte Auswahlen gefunden, siehe unten. Reparieren und erneut versuchen." -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "Vorheriger Schritt" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "Auswahl übertragen" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "Datei-Felder" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "Spalte entfernen" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "Auswahl duplizieren" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "Zeile entfernen" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "Fehler in den übermittelten Daten" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "Zeile" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "Zulieferer-Teil auswählen" @@ -3074,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "Datei zur Bestellung hochladen" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "Schritt %(step)s von %(count)s" @@ -3082,28 +3189,32 @@ msgstr "Schritt %(step)s von %(count)s" msgid "Order is already processed. Files cannot be uploaded." msgstr "Bestellung ist bereits verarbeitet. Dateien können nicht hochgeladen werden." -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "Schritt 1 von 2 - Zulieferer auswählen" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "Zulieferer auswählen" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "Keine kaufbaren Teile ausgewählt" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "Zulieferer auswählen" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "Zulieferer auswählen für %(name)s" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "Teil entfernen" @@ -3117,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "Bestellungen auswählen oder anlegen." #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "Positionen" @@ -3136,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "Bestellung für %(name)s auswählen" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "Bestellungs-Anhänge" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "Sind Sie sicher, dass Sie diese Position löschen möchten?" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "BestandsObjekte empfangen" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "Empfangene Teile" @@ -3154,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "Bestellungs-Positionen" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "Position hinzufügen" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "Position bearbeiten" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "Position löschen" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "Keine Positionen gefunden" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "Summe" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "Stück-Preis" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" -msgstr "" +msgstr "Gesamtpreis" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "Position bearbeiten" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "Position löschen" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "Position empfangen" @@ -3196,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "Ausstehende Teile für %(order)s - %(desc)s empfangen" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "Teile" @@ -3217,7 +3350,7 @@ msgid "Order Code" msgstr "Bestellnummer" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "Bestellt" @@ -3225,11 +3358,11 @@ msgstr "Bestellt" msgid "Receive" msgstr "Empfangen" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "Fehler: verknüpftes Teil wurde gelöscht" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "Position entfernen" @@ -3246,10 +3379,14 @@ msgstr "Packliste" msgid "Sales Order Details" msgstr "Auftragsdetails" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "Kundenreferenz" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "Auftrag bearbeiten" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3265,69 +3402,69 @@ msgstr "Abbruch dieser Bestellung bedeutet, dass sie nicht länger bearbeitbar i msgid "Sales Order Items" msgstr "Auftrags-Positionen" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "Aktionen" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "Bestands-Zuordnung bearbeiten" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "Bestands-Zuordnung löschen" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "Keine passenden Positionen gefunden" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "ID" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "Zugeordnet" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "Erledigt" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "PO" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "Seriennummern zuweisen" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "Lagerbestand zuweisen" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "Lagerbestand kaufen" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "Lagerbestand bauen" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "Preis berechnen" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "Position löschen " -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "Stückpreis aktualisieren" @@ -3368,195 +3505,155 @@ msgstr "Diese Aktion wird die folgenden BestandsObjekt vom Auftrag entfernen" msgid "Sales Order Attachments" msgstr "Auftrags-Anhänge" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "Sind Sie sicher, dass Sie diese Position löschen möchten?" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "Bestellungs-Anhang hinzufügen" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "Auftrags-Anhang hinzufügen" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "Auftrag anlegen" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "Bestellung bearbeiten" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "Auftrag bearbeiten" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "Bestellung stornieren" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "Bestellstornierung bestätigen" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "Bestellung kann nicht verworfen werden" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "Auftrag stornieren" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "Bestellung aufgeben" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "Bestellungstätigung bestätigen" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "Bestellung plaziert" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "Auftrag fertigstellen" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "Fertigstellung bestätigen" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "Bestellung als vollständig markieren" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "Versenden" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "Versand bestätigen" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "Versand fehlgeschlagen" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "Zuliefererteile zuordnen" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "Teile empfangen" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "Anzahl empfangener Positionen" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "Kein Ziel gesetzt" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "Fehler beim Konvertieren zu Zahl" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "Anzahl kleiner null empfangen" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "Keine Zeilen angegeben" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "{n} Teile bestellt" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "Zuliefererteil muss ausgewählt werden" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "Zulieferer muss zu Teil und Bestellung passen" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "Position bearbeiten" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "Position löschen" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "Position gelöscht" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "Seriennummern zuweisen" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "{n} Positionen zugeordnet" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "Position auswählen" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "Kein passends Teil für Seriennummer {serial} gefunden" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "{serial} ist nicht auf Lager" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "{serial} bereits einem Auftrag zugeordnet" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "Lagerbestand dem Auftrag zuweisen" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "Zuordnung bearbeiten" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "Zuordnung entfernen" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "Auftrag nicht gefunden" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "Preis nicht gefunden" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "Stückpreis für {part} auf {price} aktualisiert" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "{part} Stückpreis auf {price} und Menge auf {qty} aktualisiert" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "Standard-Lagerort" @@ -3577,143 +3674,143 @@ msgstr "Fehler beim Lesen der Stückliste (ungültige Daten)" msgid "Error reading BOM file (incorrect row size)" msgstr "Fehler beim Lesen der Stückliste (ungültige Zeilengröße)" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "Dateiformat" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "Ausgabe-Dateiformat auswählen" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "Kaskadierend" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "Kaskadierende Stückliste herunterladen" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "Ebenen" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "Maximale Anzahl an Ebenen für Stückliste-Export auswählen (0 = alle Ebenen)" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "Parameter-Daten einschließen" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "Teil-Parameter in Stückliste-Export einschließen" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "Bestand einschließen" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "Teil-Bestand in Stückliste-Export einschließen" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "Herstellerdaten einschließen" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "Teil-Herstellerdaten in Stückliste-Export einschließen" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "Zulieferer einschließen" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "Zulieferer-Daten in Stückliste-Export einschließen" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "Ausgangsteil" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "Teil für Stücklisten-Kopie auswählen" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "Stücklisten-Position(en) löschen" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "Kopie von Stückliste bestätigen" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "kontrollieren" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "Bestätigen, dass die Stückliste korrekt ist" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "Stücklisten-Datei" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "Stücklisten-Datei zum Upload auswählen" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "verknüpftes Teil" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "Teil-Kategorie wählen" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "Stückliste für dieses Teil kopieren" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "Stückliste kopieren" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "Alle Parameter-Daten für dieses Teil kopieren" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "Parameter kopieren" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "Erstellen des Teils bestätigen" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "Kategorie Parameter-Vorlage einschließen" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "Über-Kategorie Parameter-Vorlage einschließen" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "Parameter-Vorlage zu Kategorien dieser Ebene hinzufügen" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "Parameter-Vorlage zu allen Kategorien hinzufügen" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "Untergeordnetes Teil" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "Menge für die Preisberechnung" @@ -3729,392 +3826,379 @@ msgstr "Standard Stichwörter" msgid "Default keywords for parts in this category" msgstr "Standard-Stichworte für Teile dieser Kategorie" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "Teil-Kategorie" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "Teil-Kategorien" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "Teil '{p1}' wird in Stückliste für Teil '{p2}' benutzt (rekursiv)" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "Nächste verfügbare Seriennummern wären" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "Nächste verfügbare Seriennummer ist" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "Die neuste Seriennummer ist" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "Doppelte IPN in den Teil-Einstellungen nicht erlaubt" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "Namen, Teile- und Revisionsnummern müssen eindeutig sein" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "Name des Teils" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "Ist eine Vorlage" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "Ist dieses Teil eine Vorlage?" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "Ist dieses Teil eine Variante eines anderen Teils?" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "Variante von" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "Beschreibung des Teils" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "Schlüsselwörter" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "Schlüsselworte um die Sichtbarkeit in Suchergebnissen zu verbessern" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "Kategorie" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "Teile-Kategorie" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN (Interne Produktnummer)" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "Interne Teilenummer" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "Revisions- oder Versionsnummer" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "Revision" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "Standard Zulieferer" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "Standard Zuliefererteil" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "Standard Ablaufzeit" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "Ablauf-Zeit (in Tagen) für Lagerbestand dieses Teils" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "Minimaler Lagerbestand" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "Minimal zulässiger Lagerbestand" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "Einheiten" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "Stock Keeping Units (SKU) für dieses Teil" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "Kann dieses Teil aus anderen Teilen angefertigt werden?" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "Kann dieses Teil zum Bauauftrag von anderen genutzt werden?" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "Hat dieses Teil Tracking für einzelne Objekte?" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "Kann dieses Teil von externen Zulieferern gekauft werden?" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "Kann dieses Teil an Kunden verkauft werden?" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "Aktiv" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "Ist dieses Teil aktiv?" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "Ist dieses Teil virtuell, wie zum Beispiel eine Software oder Lizenz?" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "Bemerkungen - unterstüzt Markdown-Formatierung" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "Prüfsumme der Stückliste gespeichert" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "Stückliste kontrolliert von" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "BOM Kontrolldatum" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "Erstellungs-Nutzer" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "Mehrere verkaufen" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "Test-Vorlagen können nur für verfolgbare Teile angelegt werden" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "Ein Test mit diesem Namen besteht bereits für dieses Teil" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "Test-Name" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "Namen für diesen Test eingeben" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "Test-Beschreibung" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "Beschreibung für diesen Test eingeben" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "Benötigt" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "Muss dieser Test erfolgreich sein?" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "Erfordert Wert" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "Muss für diesen Test ein Wert für das Test-Ergebnis eingetragen werden?" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "Anhang muss eingegeben werden" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "Muss für diesen Test ein Anhang für das Test-Ergebnis hinzugefügt werden?" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "Name des Parameters" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "Einheit des Parameters" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "Parameter Vorlage" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "Wert" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "Parameter Wert" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "Standard-Wert" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "Standard Parameter Wert" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "Ausgangsteil auswählen" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "Teil für die Nutzung in der Stückliste auswählen" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "Stücklisten-Anzahl für dieses Stücklisten-Teil" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "Optional" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "Diese Stücklisten-Position ist optional" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "Überschuss" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "Geschätzter Ausschuss (absolut oder prozentual)" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "Referenz der Postion auf der Stückliste" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "Notizen zur Stücklisten-Position" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "Prüfsumme" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "Geerbt" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "Diese Stücklisten-Position wird in die Stücklisten von Teil-Varianten vererbt" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "Varianten zulassen" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "Lagerbestand von Varianten kann für diese Stücklisten-Position verwendet werden" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "Menge muss eine Ganzzahl sein" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "Zuliefererteil muss festgelegt sein" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "Stücklisten-Position" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "Teil 1" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "Teil 2" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "verknüpftes Teil auswählen" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "Fehler bei Verwandschaft: Ist das Teil mit sich selbst verwandt oder ist das die Verwandtschaft nicht eindeutig?" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" -msgstr "Teil-Bestandszuordnungen" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" +msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "Anhänge" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "Sind Sie sicher, dass Sie diese Stücklisten-Position löschen wollen?" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "Die Löschung dieses Eintrags wird das Stücklisten-Position vom folgenden Teil entfernen" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "Stückliste" @@ -4161,7 +4245,7 @@ msgstr "Stückliste bearbeiten" msgid "Validate Bill of Materials" msgstr "Stückliste kontrollieren" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "Stückliste exportieren" @@ -4177,8 +4261,8 @@ msgstr "Ausgewählte Stücklistenpositionen löschen?" msgid "All selected BOM items will be deleted" msgstr "Alle ausgewählte Stücklistenpositionen werden gelöscht" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "Neues Teil anlegen" @@ -4214,7 +4298,7 @@ msgid "Select Part" msgstr "Teil auswählen" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "Neues Teil anlegen" @@ -4255,90 +4339,99 @@ msgstr "Gefertigte Teile" msgid "Start New Build" msgstr "Neuen Bauauftrag beginnen" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "Alle Teile" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "Teil-Kategorie anlegen" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "Teil-Kategorie bearbeiten" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "Teil-Kategorie löschen" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "Kategorie-Details" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "Pfad zur Kategorie" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "Kategorie-Beschreibung" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "Unter-Kategorien" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "Teile (inklusive Unter-Kategorien)" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "Teile-Daten exportieren" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "Teil-Kategorie auswählen" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "Teil-Kategorie auswählen" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "Exportieren" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "Listenansicht anzeigen" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "Rasteransicht anzeigen" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "Neuen Lagerort anlegen" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "Neue Kategorie" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "Teil-Kategorie anlegen" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "Neue Teil-Kategorie anlegen" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "Neuen Lagerort erstellen" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "Teil-Kategorie bearbeiten" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "Sind Sie sicher, dass Sie diese Kategorie löschen wollen" @@ -4374,18 +4467,17 @@ msgstr "Wenn diese Kat. gelöscht wird, werden diese Teile in die übergeordnete msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "Wenn diese Kat. gelöscht wird, werden diese Teile in die oberste Kat. verschoben" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "Parameter" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" +msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "Teilparameter" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "Teil duplizieren" @@ -4409,7 +4501,7 @@ msgstr "Teil evtl. Duplikat dieser Teile" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "%(full_name)s - %(desc)s (%(match_per)s%% übereinstimmend)" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "Teil Details" @@ -4489,6 +4581,15 @@ msgstr "Teil ist aktiv" msgid "Part is not active" msgstr "Teil ist nicht aktiv" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "Teil-Hersteller" @@ -4498,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "Herstellerteile löschen" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "Neuen Hersteller anlegen" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "Teil Varianten" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "Varianten" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "Lagerbestand zuweisen" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "Zuweisungen" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "Benutzt in" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" -msgstr "Bestellpreisinformationen" +#: part/templates/part/navbar.html:77 +msgid "Prices" +msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "Bestellpreis" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "Preisinformationen ansehen" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "Teil Test-Vorlagen" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "Tests" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "Verknüpfte Teile" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "Teil-Bemerkungen" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "Preisspannen" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "Zulieferer-Preise" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "Stückpreis" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "Gesamtkosten" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "Keine Zulieferer-Preise verfügbar" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "Stücklistenpreise" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "Anmerkung: Stücklistenbepreisung für dieses Teil ist unvollständig" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "Keine Stücklisten-Preise verfügbar" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "Keine Preise für dieses Teil verfügbar" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "Bestandspreise" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "Für dieses Teil sind keine Bestandspreise verfügbar." - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "Einzelpreis - %(currency)s" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "Einzelpreisdifferenz - %(currency)s" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "Einzelpreis für Zuliefererteil- %(currency)s" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "Parameter hinzufügen" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "Neuer Parameter" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "Wert" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "Bearbeiten" @@ -4660,8 +4664,8 @@ msgstr "Neue Teilparametervorlage anlegen" msgid "Part List" msgstr "Teileliste" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "Inaktiv" @@ -4724,7 +4728,7 @@ msgstr "Dieses Teil ist eine Variante von %(link)s" msgid "In Stock" msgstr "Auf Lager" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "Für Bauaufträge benötigt" @@ -4736,23 +4740,95 @@ msgstr "Benötigt für Aufträge" msgid "Allocated to Orders" msgstr "Zu Bauaufträgen zugeordnet" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "Herstellbar" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "Im Bau" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "Berechnen" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "Zulieferer-Preise" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "Stückpreis" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "Gesamtkosten" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "Keine Zulieferer-Preise verfügbar" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "Stücklistenpreise" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "Anmerkung: Stücklistenbepreisung für dieses Teil ist unvollständig" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "Keine Stücklisten-Preise verfügbar" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "Interner Preis" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "Keine Preise für dieses Teil verfügbar" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "Test Vorlage hinzufügen" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "Aus vorhandenen Bildern auswählen" @@ -4787,14 +4863,100 @@ msgstr "Es sind %(count)s Zulieferer für diesen Teil definiert. Wenn Sie diesen msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "Es gibt %(count)s einzigartige Teile, die für '%(full_name)s' verfolgt werden. Das Löschen dieses Teils wird diese Tracking-Informationen dauerhaft entfernen." +#: part/templates/part/prices.html:12 +msgid "General Price Information" +msgstr "" + +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "Preisspannen" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "Bestandspreise" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "Für dieses Teil sind keine Bestandspreise verfügbar." + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "Einzelpreis - %(currency)s" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "Einzelpreisdifferenz - %(currency)s" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "Einzelpreis für Zuliefererteil- %(currency)s" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + #: part/templates/part/related.html:18 msgid "Add Related" msgstr "Verknüpftes Teil hinzufügen" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" -msgstr "Verkaufspreis Informationen" - #: part/templates/part/sales_orders.html:18 msgid "New sales order" msgstr "Neuer Auftrag" @@ -4817,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "Lagerbestand aller Varianten von %(full_name)s" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "Kein Bestand" @@ -4854,296 +5016,276 @@ msgstr "Neue Variante anlegen" msgid "New Variant" msgstr "neue Variante anlegen" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "Unbekannte Datenbank" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "verknüpftes Teil hinzufügen" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "verknüpftes Teil entfernen" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "Teilanhang hinzufügen" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "Anhang bearbeiten" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "Teilanhang aktualisiert" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "Teilanhang löschen" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "Teilanhang gelöscht" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "Testvorlage anlegen" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "Testvorlage bearbeiten" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "Testvorlage löschen" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "Teil-Kategorie auswählen" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "Kategorie für {n} Teile setzen" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "Variante anlegen" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "Teil kopiert" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "Übereinstimmung gefunden - Teil trotzdem anlegen" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "Neues Teil angelegt" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "Teil-QR-Code" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "Teilbild hochladen" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "Teilbild aktualisiert" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "Teilbild auswählen" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "Teilbild aktualisiert" + +#: part/views.py:1115 msgid "Part image not found" msgstr "Teilbild nicht gefunden" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "Teileigenschaften bearbeiten" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "Stückliste duplizieren" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "bestätige Duplizierung Stückliste von übergeordneter Stückliste" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "Stückliste überprüfen" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "Bestätigen, dass Stückliste korrekt ist" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "überprüfte Stückliste" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "Keine Stückliste angegeben" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "Bitte eine gültige Anzahl eingeben" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "Bitte ein gültiges Teil auswählen" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "Teil doppelt ausgewählt" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "Teil auswählen" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "gewähltes Teil erzeugt rekursive Stückliste" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "Anzahl angeben" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "Löschen des Teils bestätigen" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "Teil wurde gelöscht" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "Teilbepreisung" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "Teilparametervorlage anlegen" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "Teilparametervorlage bearbeiten" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "Teilparametervorlage löschen" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "Teilparameter anlegen" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "Teilparameter bearbeiten" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "Teilparameter löschen" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "Teil-Kategorie bearbeiten" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "Teil-Kategorie löschen" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "Teil-Kategorie wurde gelöscht" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "Kategorieparametervorlage anlegen" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "Kategorieparametervorlage bearbeiten" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "Kategorieparametervorlage löschen" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "Stücklisten-Position anlegen" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "Stücklisten-Position bearbeiten" -#: part/views.py:2725 -msgid "Confim BOM item deletion" -msgstr "löschen von Stücklisten-Position bestätigen" +#: part/views.py:2792 +msgid "Added new price break" +msgstr "neue Preisstaffel hinzufügt" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "Vorlagen Name" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "Bericht-Vorlage Datei" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "Bericht-Vorlage Beschreibung" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "Bericht Revisionsnummer (autom. erhöht)" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "Muster für die Erstellung von Berichtsdateinamen" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "Bericht-Vorlage ist ein" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "BestandsObjekte-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "einfügen Installiert in Tests" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "Test-Ergebnisse für BestandsObjekte in Baugruppen einschließen" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "Bauauftrag Filter" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "Bau-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "Teil Filter" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "Teile-Abfragefilter (kommagetrennte Liste mit Schlüssel=Wert-Paaren)" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "Bestellungs-Abfragefilter" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "Auftrags-Abfragefilter" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "Snippet" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "Berichts-Snippet" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "Snippet-Beschreibung" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "Ressource" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "Berichts-Ressource" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "Ressource-Beschreibung" @@ -5165,17 +5307,17 @@ msgid "Test Results" msgstr "Testergebnisse" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "Test" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "Ergebnis" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "Datum" @@ -5187,287 +5329,287 @@ msgstr "bestanden" msgid "Fail" msgstr "fehlgeschlagen" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "Bestand für {n} Objekte geändert" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "{n} Teile nach {loc} bewegt" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "Ablaufdatum" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "Ablaufdatum für dieses BestandsObjekt" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "Eindeutige Seriennummern eingeben (oder leer lassen)" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "Lagerort für serial" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "Seriennummern" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "Anzahl der eindeutigen Seriennummern (muss mit der Anzahl übereinstimmen)" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr " Transaktionsnotizen hinzufügen (optional)" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "Test Bericht Vorlage auswählen" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "Unter-Lagerorte einschließen" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "BestandsObjekt in untergeordneten Lagerorten einschließen" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "BestandsObjekt zum verbauen" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "Bestandmenge zum Zuweisen" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "Anzahl darf die verfügbare Anzahl nicht überschreiten" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "Ziel Lagerort für unverbaute Objekte" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "nicht mehr verbauen bestätigen" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "Entfernen der verbauten BestandsObjekt bestätigen" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "Ziel-Lagerbestand" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "Notiz hinzufügen (erforderlich)" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "Bestands-Anpassung bestätigen" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "Verschieben der BestandsObjekt bestätigen" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "Standard-Lagerort ändern" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "Setze das Ziel als Standard-Lagerort für ausgewählte Teile" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "Besitzer" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "Besitzer auswählen" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "Ein BestandsObjekt mit dieser Seriennummer existiert bereits" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "Teile-Typ ('{pf}') muss {pe} sein" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "Anzahl muss für Objekte mit Seriennummer 1 sein" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "Seriennummer kann nicht gesetzt werden wenn die Anzahl größer als 1 ist" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "Teil kann nicht zu sich selbst gehören" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "Teil muss eine Referenz haben wenn is_building wahr ist" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "Referenz verweist nicht auf das gleiche Teil" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "Eltern-BestandsObjekt" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "Basis-Teil" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "Passendes Zuliefererteil für dieses BestandsObjekt auswählen" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "Bestand-Lagerort" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "Die Verpackung dieses BestandsObjekt ist gelagert in" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "verbaut in" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "Ist dieses Teil in einem anderen verbaut?" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "Seriennummer für dieses Teil" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "Losnummer für dieses BestandsObjekt" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "Bestand" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "Quellbau" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "Bauauftrag für dieses BestandsObjekt" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "Quelle Bestellung" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "Bestellung für dieses BestandsObjekt" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "Ziel-Auftrag" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "Ablaufdatum für BestandsObjekt. Bestand wird danach als abgelaufen gekennzeichnet" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "Löschen wenn leer" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "Dieses BestandsObjekt löschen wenn Bestand aufgebraucht" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "BestandsObjekt-Notizen" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "Preis für eine Einheit bei Einkauf" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "Teil ist nicht verfolgbar" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: stock/models.py:1023 +#: stock/models.py:1026 #, 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:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "Seriennummern muss eine Liste von Ganzzahlen sein" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "Anzahl stimmt nicht mit den Seriennummern überein" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "Seriennummern {exists} existieren bereits" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "BestandsObjekt kann nicht bewegt werden, da kein Bestand vorhanden ist" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "Eintrags-Notizen" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "Wert muss für diesen Test angegeben werden" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "Anhang muss für diesen Test hochgeladen werden" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "Name des Tests" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "Testergebnis" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "Test Ausgabe Wert" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "Test Ergebnis Anhang" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "Test Notizen" @@ -5484,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "BestandsObjekt-Anhang" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "abgelaufen" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "überfällig" @@ -5619,7 +5761,7 @@ msgstr "Dieses BestandsObjekt wird automatisch gelöscht wenn der Lagerbestand a msgid "Stock Item Details" msgstr "BestandsObjekt-Details" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "Kein Lagerort gesetzt" @@ -5631,28 +5773,36 @@ msgstr "Barcode-Bezeichner" msgid "Parent Item" msgstr "Elternposition" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "Dieses BestandsObjekt lief am %(item.expiry_date)s ab" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "Dieses BestandsObjekt läuft am %(item.expiry_date)s ab" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "Zuletzt aktualisiert" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "Letzte Inventur" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "Keine Inventur ausgeführt" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "Kind-BestandsObjekt" @@ -5712,6 +5862,19 @@ msgstr "Testdaten löschen" msgid "Add Test Data" msgstr "Testdaten hinzufügen" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "Testergebnis hinzufügen" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "Testergebnis bearbeiten" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "Testergebnis löschen" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "Sie sind nicht auf der Liste der Besitzer dieses Lagerorts. Der Bestands-Lagerort kann nicht verändert werden." @@ -5760,7 +5923,7 @@ msgid "Stock Details" msgstr "Objekt-Details" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "Bestand-Lagerorte" @@ -5800,7 +5963,7 @@ msgstr "Lade..." msgid "The following stock items will be uninstalled" msgstr "Die folgenden BestandsObjekte werden nicht mehr verbaut" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "BestandsObjekt umwandeln" @@ -5833,8 +5996,8 @@ msgstr "Sind Sie sicher, dass Sie diesen BestandsObjekt-Verfolgungs-Eintrag lös msgid "Edit Stock Location" msgstr "BestandsObjekt-Lagerort bearbeiten" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "Eigentümer notwendig (Eigentümerkontrolle aktiv)" @@ -5842,205 +6005,177 @@ msgstr "Eigentümer notwendig (Eigentümerkontrolle aktiv)" msgid "Stock Location QR code" msgstr "QR-Code für diesen Lagerort" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "BestandsObjekt-Anhang hinzufügen" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "BestandsObjekt-Anhang bearbeiten" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "BestandsObjekt-Anhang löschen" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "Kunden zuweisen" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "Kunde muss angegeben werden" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "zurück ins Lager" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "gültigen Lagerort angeben" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "BestandsObjekt retoure vom Kunden" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "alle Testdaten löschen" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "Löschen Testdaten bestätigen" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "Testergebnis hinzufügen" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "Testergebnis bearbeiten" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "Testergebnis löschen" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "Lagerbestand Exportoptionen" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "BestandsObjekt-QR-Code" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "BestandsObjekt installiert" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "BestandsObjekte deinstallieren" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "BestandsObjekte deinstalliert" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "Lagerbestand anpassen" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "BestandsObjekte bewegen" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "Verschieben" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "BestandsObjekte zählen" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "Anzahl" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "Aus Lagerbestand entfernen" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "Entfernen" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "BestandsObjekte hinzufügen" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "Hinzufügen" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "BestandsObjekte löschen" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "Nur Ganzzahl eingeben" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "Anzahl muss positiv sein" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "Anzahl darf {x} nicht überschreiten" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "Keine Aktion durchgeführt" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "Vorrat zu {n} BestandsObjekten hinzugefügt" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "Vorrat von {n} BestandsObjekten entfernt" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "Bestand für {n} Objekte erfasst" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "Keine BestandsObjekt wurden bewegt" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "{n} Teile nach {dest} bewegt" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "{n} BestandsObjekte gelöscht" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "Status bearbeiten" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "BestandsObjekt bearbeiten" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "Lagerbestand erfassen" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "Neues BestandsObjekt hinzufügen" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "Bestand duplizieren" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "Anzahl kann nicht negativ sein" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "Bestand-Lagerort löschen" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "BestandsObjekt löschen" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag löschen" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag bearbeiten" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag hinzufügen" @@ -6080,35 +6215,39 @@ msgstr "Stücklisten erwarten Kontrolle" msgid "Recently Updated" msgstr "kürzlich aktualisiert" -#: templates/InvenTree/index.html:145 +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" +msgstr "" + +#: templates/InvenTree/index.html:146 msgid "Expired Stock" msgstr "abgelaufener Bestand" -#: templates/InvenTree/index.html:146 +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "Lagerbestand überfällig" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "laufende Bauaufträge" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "überfällige Bauaufträge" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "ausstehende Bestellungen" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "überfällige Bestellungen" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "ausstehende Aufträge" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "überfällige Aufträge" @@ -6120,11 +6259,11 @@ msgstr "Suchergebnisse" msgid "Enter a search query" msgstr "Eine Sucheanfrage eingeben" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "an Kunde versand" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "Kein Lagerort gesetzt" @@ -6172,12 +6311,12 @@ msgid "No category parameter templates found" msgstr "Keine Kategorie-Parametervorlagen gefunden" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "Vorlage bearbeiten" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "Vorlage löschen" @@ -6185,23 +6324,23 @@ msgstr "Vorlage löschen" msgid "Currency Settings" msgstr "Währungseinstellungen" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "Basiswährung" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "Wechselkurse" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "Letzte Aktualisierung" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "Nie" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "Jetzt aktualisieren" @@ -6225,11 +6364,19 @@ msgstr "Teil-Einstellungen" msgid "Part Options" msgstr "Teil-Optionen" -#: templates/InvenTree/settings/part.html:40 +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" +msgstr "" + +#: templates/InvenTree/settings/part.html:61 msgid "Part Parameter Templates" msgstr "Teil-Parametervorlage" -#: templates/InvenTree/settings/part.html:61 +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "Keine Teilparametervorlagen gefunden" @@ -6345,63 +6492,55 @@ msgid "API Version" msgstr "API-Version" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "Django-Version" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "Commit-Hash" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "Commit-Datum" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "InvenTree-Dokumentation" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "Code auf GitHub ansehen" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "Danksagung" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "Mobile App" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "Fehlerbericht senden" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "In die Zwischenablage kopieren" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "Versionsinformationen kopieren" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "Schliessen" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "Anhang hinzufügen" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "Hochgeladen" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "Anhang löschen" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "URL für Bild-Donwload angeben" @@ -6418,6 +6557,22 @@ msgstr "Der angegebene Server muss erreichbar sein" msgid "Remote image must not exceed maximum allowable file size" msgstr "Das Bild darf nicht größer als die maximal-erlaubte Größe sein" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "Anhang bearbeiten" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "Anhang löschen" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "Hier den Barcode scannen" @@ -6446,7 +6601,7 @@ msgstr "Server-Fehler" msgid "Unknown response from server" msgstr "Unbekannte Antwort von Server erhalten" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "Ungültige Antwort von Server" @@ -6510,7 +6665,7 @@ msgstr "In Lagerorten buchen" msgid "Barcode does not match a valid location" msgstr "Barcode entspricht keinem Lagerort" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "Unterbaugruppe öffnen" @@ -6522,31 +6677,35 @@ msgstr "Kaufpreisspanne" msgid "Purchase Price Average" msgstr "Durchschnittlicher Kaufpreis" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "Keine Preisinformation verfügbar" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "Stückliste anzeigen" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "Stücklisten-Position kontrollieren" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "Diese Position wurde kontrolliert" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "Stücklisten-Position bearbeiten" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "Stücklisten-Position löschen" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "Keine Stücklisten-Position(en) gefunden" @@ -6566,67 +6725,111 @@ msgstr "Endprodukt fertigstellen" msgid "Delete build output" msgstr "Endprodukt entfernen" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "Standort nicht angegeben" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "Neues BestandsObjekt" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "benötigtes Teil" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "Anzahl pro" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "Bestand bestellen" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "Keine Bauaufträge passen zur Anfrage" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "Auswählen" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "Bauauftrag ist überfällig" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "Keine Teile zugeordnet zu" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "Firma bearbeiten" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "Teile geliefert" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "Hersteller-Teile" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "Keine Firmeninformation gefunden" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "Keine Herstellerteile gefunden" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "Vorlagenteil" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "Baugruppe" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "Keine Zuliefererteile gefunden" @@ -6654,6 +6857,83 @@ msgstr "Filter entfernen" msgid "Create filter" msgstr "Filter anlegen" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "Keine Antwort" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "keine Antwort vom InvenTree Server" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "Fehler 401: Nicht Angemeldet" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "Authentication Kredentials nicht angegeben" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "Fehler 403: keine Berechtigung" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "Fehlende Berechtigung für diese Aktion" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "Fehler 404: Ressource nicht gefunden" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "Die angefragte Ressource kann auf diesem Server nicht gefunden werden" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "Fehler 408: Zeitüberschreitung" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "Verbindungszeitüberschreitung bei der Datenanforderung" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "Fehler bei Formulardaten-Anfrage" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "Fehler in Formular" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "BestandsObjekte auswählen" @@ -6694,111 +6974,105 @@ msgstr "Label auswählen" msgid "Select Label Template" msgstr "Label-Vorlage auswählen" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "Warte auf Server..." - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "Fehler-Informationen anzeigen" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "Akzeptieren" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "abbrechen" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "Lade Daten" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "Abschicken" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "Warte auf Server..." + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "Fehler-Informationen anzeigen" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "Akzeptieren" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "Lade Daten" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "ungültige Antwort vom Server" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "Formulardaten fehlen bei Serverantwort" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "Formulardaten fehlerhaft" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "JSON Antwort enthält keine Formulardaten" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "Keine Antwort" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "keine Antwort vom InvenTree Server" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "Fehler 400: Ungültige Anfrage" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "Fehler 400 von Server erhalten" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" -msgstr "Fehler 401: Nicht Angemeldet" +#: templates/js/model_renderers.js:21 +msgid "Company ID" +msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" -msgstr "Authentication Kredentials nicht angegeben" +#: templates/js/model_renderers.js:63 +msgid "Location ID" +msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" -msgstr "Fehler 403: keine Berechtigung" +#: templates/js/model_renderers.js:90 +msgid "Part ID" +msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" -msgstr "Fehlende Berechtigung für diese Aktion" +#: templates/js/model_renderers.js:126 +msgid "Category ID" +msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" -msgstr "Fehler 404: Ressource nicht gefunden" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" +msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" -msgstr "Die angefragte Ressource kann auf diesem Server nicht gefunden werden" +#: templates/js/order.js:31 +msgid "Create Sales Order" +msgstr "Auftrag anlegen" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "Fehler 408: Zeitüberschreitung" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "Verbindungszeitüberschreitung bei der Datenanforderung" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "Fehler bei Formulardaten-Anfrage" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "Keine Bestellungen gefunden" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "Bestellung überfällig" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "Keine Aufträge gefunden" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "JA" @@ -6827,39 +7101,54 @@ msgstr "Verkäufliches Teil" msgid "No variants found" msgstr "Keine Varianten gefunden" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "Keine Teile gefunden" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "Keine Kategorie" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "Bestand niedrig" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "Pfad" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "Keine zur Anfrage passenden Testvorlagen" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "Testergebnis bearbeiten" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "Testergebnis löschen" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "Dieses Testergebnis ist für ein Hauptteil" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "Einzelpreisdifferenz" @@ -6957,155 +7246,155 @@ msgstr "Keine Testergebnisse gefunden" msgid "Test Date" msgstr "Testdatum" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "In Arbeit" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "In BestandsObjekt installiert" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "Auftrag zugewiesen" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "Keine zur Anfrage passenden BestandsObjekte" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "Teile" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "lose" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "Lagerorte" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "unbekannter Lagerort" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "BestandsObjekt wird produziert" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "BestandsObjekt wurde Auftrag zugewiesen" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "BestandsObjekt wurde Kunden zugewiesen" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "BestandsObjekt ist abgelaufen" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "BestandsObjekt läuft demnächst ab" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "BestandsObjekt zugewiesen" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "BestandsObjekt in anderem Element verbaut" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "BestandsObjekt abgewiesen" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "BestandsObjekt verloren" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "BestandsObjekt zerstört" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "gelöscht" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "Inventur" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "Status" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "Status setzen" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "Status Code setzen" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "Status Code muss ausgewählt werden" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "Ungültiges Datum" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "Standort nicht mehr vorhanden" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "Bestellung existiert nicht mehr" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "Kunde existiert nicht mehr" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "Lagerbestand existiert nicht mehr" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "Hinzugefügt" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "Entfernt" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "Keine Benutzerinformation" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "Tracking-Eintrag bearbeiten" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "Tracking-Eintrag löschen" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "Neuen Lagerort anlegen" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "Keine installierten Elemente" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "Seriennummer" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "Lagerbestand entfernen" @@ -7126,7 +7415,7 @@ msgid "Include locations" msgstr "Lagerorte einschließen" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "Unterkategorien einschließen" @@ -7159,7 +7448,7 @@ msgstr "Seriennummer" msgid "Batch code" msgstr "Losnummer" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "Aktive Teile" @@ -7231,103 +7520,107 @@ msgstr "zeige zu Kunden zugeordnete Einträge" msgid "Stock status" msgstr "Status" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "Bauauftrags-Status" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "Bestellstatus" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "ausstehend" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "Teile in Unterkategorien einschließen" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "Hat IPN" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "Teil hat Interne Teilenummer" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "Aktive Teile anzeigen" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "verfügbarer Lagerbestand" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "Favorit" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "Käuflich" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "Lade Daten" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "Zeilen pro Seite" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "zeige" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "bis" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "von" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "Zeilen" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "Suche" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "Keine passenden Ergebnisse gefunden" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "Zeige/Verstecke Pagination" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "Neu laden" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "umschalten" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "Spalten" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "Alle" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "Fehler in Formular" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "Navigation ein-/ausklappen" @@ -7344,7 +7637,7 @@ msgstr "Verkaufen" msgid "Scan Barcode" msgstr "Barcode scannen" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "Admin" @@ -7564,35 +7857,35 @@ msgstr "Berechtigungen" msgid "Important dates" msgstr "wichtige Daten" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "Berechtigung geändert" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "Gruppe" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "Ansicht" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "Berechtigung Einträge anzuzeigen" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "Berechtigung Einträge zu erstellen" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "Ändern" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "Berechtigungen Einträge zu ändern" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "Berechtigung Einträge zu löschen" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index ab3c93408d..ba01b18cb4 100644 --- a/InvenTree/locale/en/LC_MESSAGES/django.po +++ b/InvenTree/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -30,14 +30,14 @@ msgstr "" msgid "No matching action found" msgstr "" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "" @@ -73,134 +73,143 @@ msgstr "" msgid "Select Category" msgstr "" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "" -#: InvenTree/settings.py:503 -msgid "English" -msgstr "" - -#: InvenTree/settings.py:504 -msgid "French" +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" msgstr "" #: InvenTree/settings.py:505 -msgid "German" +msgid "English" msgstr "" #: InvenTree/settings.py:506 -msgid "Polish" +msgid "French" msgstr "" #: InvenTree/settings.py:507 +msgid "German" +msgstr "" + +#: InvenTree/settings.py:508 +msgid "Polish" +msgstr "" + +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -373,27 +382,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -446,50 +455,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "" @@ -501,7 +508,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "" @@ -530,12 +537,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "" @@ -544,13 +551,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "" @@ -582,286 +589,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -881,7 +886,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -895,8 +900,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -914,23 +919,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -979,7 +1013,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -991,8 +1025,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1038,14 +1072,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1186,7 +1219,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1195,15 +1231,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1211,7 +1247,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1249,9 +1285,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "" @@ -1286,8 +1322,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1316,7 +1351,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1332,7 +1367,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1412,8 +1447,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1429,60 +1464,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1503,7 +1513,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1520,310 +1530,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1831,25 +1889,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1857,257 +1920,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2121,7 +2230,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2129,7 +2238,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2143,16 +2253,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "" -"There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2167,11 +2270,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2192,7 +2295,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2200,7 +2304,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2214,26 +2318,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2243,40 +2346,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2311,19 +2411,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2334,13 +2434,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2360,17 +2460,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2381,14 +2513,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2398,11 +2530,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2410,11 +2542,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2443,8 +2575,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2489,449 +2622,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2957,7 +3042,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2976,16 +3061,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3016,57 +3107,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3075,6 +3180,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3083,28 +3190,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3118,7 +3229,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3137,15 +3248,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3155,34 +3270,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3197,15 +3330,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3218,7 +3351,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3226,11 +3359,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3247,10 +3380,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3266,69 +3403,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3369,195 +3506,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3578,143 +3675,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3730,392 +3827,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4162,7 +4246,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4178,8 +4262,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4215,7 +4299,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4256,90 +4340,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4375,18 +4468,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4410,7 +4502,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4490,6 +4582,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4499,152 +4600,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4661,8 +4665,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4725,7 +4729,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4737,23 +4741,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4788,12 +4864,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4818,7 +4980,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4855,296 +5017,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5166,17 +5308,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5188,287 +5330,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5485,12 +5627,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5620,7 +5762,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5632,28 +5774,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5713,6 +5863,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5761,7 +5924,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5801,7 +5964,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5834,8 +5997,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5843,205 +6006,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6081,35 +6216,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6121,11 +6260,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6171,12 +6310,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6184,23 +6323,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6224,11 +6363,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6344,63 +6491,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6417,6 +6556,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6445,7 +6600,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6509,7 +6664,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6521,31 +6676,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6565,67 +6724,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6653,6 +6856,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6693,111 +6973,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6826,39 +7100,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6956,155 +7245,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7125,7 +7414,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7158,7 +7447,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7230,103 +7519,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7343,7 +7636,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7563,34 +7856,34 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index 6d0f3375c4..9968d727ff 100644 --- a/InvenTree/locale/es/LC_MESSAGES/django.po +++ b/InvenTree/locale/es/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Spanish\n" "Language: es_ES\n" @@ -19,42 +19,42 @@ msgstr "" #: InvenTree/api.py:64 msgid "API endpoint not found" -msgstr "" +msgstr "endpoint API no encontrado" #: InvenTree/api.py:110 msgid "No action specified" -msgstr "" +msgstr "No se especificó ninguna acción" #: InvenTree/api.py:124 msgid "No matching action found" -msgstr "" +msgstr "No se encontró ninguna acción coincidente" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" -msgstr "" +msgstr "Ingrese la fecha" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Confirmar" #: InvenTree/forms.py:128 msgid "Confirm delete" -msgstr "" +msgstr "Confirmar eliminación" #: InvenTree/forms.py:129 msgid "Confirm item deletion" -msgstr "" +msgstr "Confirmar borrado de artículo" #: InvenTree/forms.py:161 templates/registration/login.html:76 msgid "Enter password" -msgstr "" +msgstr "Introduzca contraseña" #: InvenTree/forms.py:162 msgid "Enter new password" -msgstr "" +msgstr "Ingrese su nueva contraseña" #: InvenTree/forms.py:169 msgid "Confirm password" @@ -66,151 +66,160 @@ msgstr "Confirmar contraseña nueva" #: InvenTree/forms.py:205 msgid "Apply Theme" -msgstr "" +msgstr "Aplicar tema" #: InvenTree/forms.py:235 msgid "Select Category" -msgstr "" +msgstr "Seleccionar Categoría" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" -msgstr "" +msgstr "Cantidad proporcionada no válida" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" -msgstr "" +msgstr "Grupo no válido: un {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" -msgstr "" +msgstr "Numeros de serie no encontrados" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Comentario" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Usuario" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Nombre" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Descripción" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "Inglés" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Francés" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Alemán" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Polaco" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Turco" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" #: InvenTree/status_codes.py:104 InvenTree/status_codes.py:145 #: InvenTree/status_codes.py:314 msgid "Pending" -msgstr "" +msgstr "Pendiente" #: InvenTree/status_codes.py:105 msgid "Placed" -msgstr "" +msgstr "Colocado" #: InvenTree/status_codes.py:106 InvenTree/status_codes.py:317 msgid "Complete" @@ -234,7 +243,7 @@ msgstr "" #: InvenTree/status_codes.py:146 #: order/templates/order/sales_order_base.html:126 msgid "Shipped" -msgstr "" +msgstr "Enviado" #: InvenTree/status_codes.py:186 msgid "OK" @@ -254,7 +263,7 @@ msgstr "Destruido" #: InvenTree/status_codes.py:191 msgid "Rejected" -msgstr "" +msgstr "Rechazado" #: InvenTree/status_codes.py:272 msgid "Legacy stock tracking entry" @@ -262,31 +271,31 @@ msgstr "" #: InvenTree/status_codes.py:274 msgid "Stock item created" -msgstr "" +msgstr "Artículo de stock creado" #: InvenTree/status_codes.py:276 msgid "Edited stock item" -msgstr "" +msgstr "Elemento de stock editado" #: InvenTree/status_codes.py:277 msgid "Assigned serial number" -msgstr "" +msgstr "Número de serie asignado" #: InvenTree/status_codes.py:279 msgid "Stock counted" -msgstr "" +msgstr "Stock contado" #: InvenTree/status_codes.py:280 msgid "Stock manually added" -msgstr "" +msgstr "Stock añadido manualmente" #: InvenTree/status_codes.py:281 msgid "Stock manually removed" -msgstr "" +msgstr "Stock eliminado manualmente" #: InvenTree/status_codes.py:283 msgid "Location changed" -msgstr "" +msgstr "Ubicación cambiada" #: InvenTree/status_codes.py:285 msgid "Installed into assembly" @@ -326,11 +335,11 @@ msgstr "" #: InvenTree/status_codes.py:298 msgid "Build order output completed" -msgstr "" +msgstr "Construir orden de salida completado" #: InvenTree/status_codes.py:300 msgid "Received against purchase order" -msgstr "" +msgstr "Recibido contra la orden de compra" #: InvenTree/status_codes.py:315 msgid "Production" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Eliminar elemento" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Configurar Contraseña" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Información del sistema" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "Cantidad" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "Números de serie" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "Unicación" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "Estado" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "Referencia" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "Parte" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "Elementos completados" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Responsable" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "Notas" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "Número de serie" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "Progreso" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "Destinación" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Lote" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "Completados" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "Detalles" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Guardar" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "días" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "Página web" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "Teléfono" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "Teléfono de contacto" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "Email" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "Contacto" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "Fabricante" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "Proveedor" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Nota" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "Teléfono" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "Cliente" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "Opciones" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "Exportar" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "Eliminar" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "Fabricantes" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/fr/LC_MESSAGES/django.po b/InvenTree/locale/fr/LC_MESSAGES/django.po index 97617764a4..3b11868014 100644 --- a/InvenTree/locale/fr/LC_MESSAGES/django.po +++ b/InvenTree/locale/fr/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: French\n" "Language: fr_FR\n" @@ -29,14 +29,14 @@ msgstr "Aucune action spécifiée" msgid "No matching action found" msgstr "Aucune action correspondante trouvée" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "Entrer la date" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Confirmer" @@ -72,134 +72,143 @@ msgstr "Appliquer le thème" msgid "Select Category" msgstr "Sélectionnez une catégorie" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Dupliquer le numéro de série: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "Quantité fournie invalide" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "Chaîne de numéro de série vide" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "Groupe invalide : {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "Numéro de série dupliqué: {g}" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "Aucun numéro de série trouvé" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "Le nombre de numéros de série uniques ({s}) doit correspondre à la quantité ({q})" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "Pièce jointe" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "Sélectionnez un fichier à joindre" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Commentaire" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "Commentaire du fichier" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Utilisateur" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "date de chargement" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Nom" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Description" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "Description (facultative)" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "parent" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "Anglais" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Français" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Allemand" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Polonais" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Turc" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Échec de la vérification du processus d'arrière-plan" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Backend d'email non configuré" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "Échec des contrôles de santé du système" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Supprimer cet élément" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Modifier les informations utilisateur" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Informations système" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "Quantité" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "Numéros de série" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "Emplacement des pièces terminées" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "Référence" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "Pièce" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "Sélectionnez la pièce à construire" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "Date de création" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "Lien Externe" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "Notes" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "L'élément de construction doit spécifier une sortie de construction, la pièce maîtresse étant marquée comme objet traçable" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "L'article en stock sélectionné n'a pas été trouvé dans la BOM pour la pièce '{p}'" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "Commander les pièces requises" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "Commander des pièces" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Pieces jointes" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "Détails" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Enregistrer" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "Disponible" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "Pièce jointe ajoutée" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "Sélectionner un fichier à téléverser" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "{name.title()} Fichier" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" -msgstr "Télécharger depuis l'URL" +msgid "Default Currency" +msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" -msgstr "" +msgid "Download from URL" +msgstr "Télécharger depuis l'URL" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 +msgid "Barcode Support" +msgstr "" + +#: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 msgid "IPN Regex" msgstr "Regex IPN" -#: common/models.py:100 +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "Expression régulière pour la correspondance avec l'IPN de la Pièce" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "Autoriser les IPN dupliqués" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "Permettre à plusieurs pièces de partager le même IPN" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "Autoriser l'édition de l'IPN" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "Permettre de modifier la valeur de l'IPN lors de l'édition d'une pièce" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "jours" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "IPN dupliqué non autorisé dans les paramètres de la pièce" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "La pièce doit être unique par son nom, son IPN et sa révision" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "A un IPN" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/it/LC_MESSAGES/django.po b/InvenTree/locale/it/LC_MESSAGES/django.po index 6caf5cb88d..ae1f42af1e 100644 --- a/InvenTree/locale/it/LC_MESSAGES/django.po +++ b/InvenTree/locale/it/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Italian\n" "Language: it_IT\n" @@ -29,14 +29,14 @@ msgstr "" msgid "No matching action found" msgstr "" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "" @@ -72,134 +72,143 @@ msgstr "" msgid "Select Category" msgstr "" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "" -#: InvenTree/settings.py:503 -msgid "English" -msgstr "" - -#: InvenTree/settings.py:504 -msgid "French" +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" msgstr "" #: InvenTree/settings.py:505 -msgid "German" +msgid "English" msgstr "" #: InvenTree/settings.py:506 -msgid "Polish" +msgid "French" msgstr "" #: InvenTree/settings.py:507 +msgid "German" +msgstr "" + +#: InvenTree/settings.py:508 +msgid "Polish" +msgstr "" + +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/ja/LC_MESSAGES/django.po b/InvenTree/locale/ja/LC_MESSAGES/django.po index f5afd1b0fe..8ffaee4eda 100644 --- a/InvenTree/locale/ja/LC_MESSAGES/django.po +++ b/InvenTree/locale/ja/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Japanese\n" "Language: ja_JP\n" @@ -29,14 +29,14 @@ msgstr "" msgid "No matching action found" msgstr "" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "" @@ -72,134 +72,143 @@ msgstr "" msgid "Select Category" msgstr "" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "" -#: InvenTree/settings.py:503 -msgid "English" -msgstr "" - -#: InvenTree/settings.py:504 -msgid "French" +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" msgstr "" #: InvenTree/settings.py:505 -msgid "German" +msgid "English" msgstr "" #: InvenTree/settings.py:506 -msgid "Polish" +msgid "French" msgstr "" #: InvenTree/settings.py:507 +msgid "German" +msgstr "" + +#: InvenTree/settings.py:508 +msgid "Polish" +msgstr "" + +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/pl/LC_MESSAGES/django.po b/InvenTree/locale/pl/LC_MESSAGES/django.po index 9b4e347ff7..e7b0087141 100644 --- a/InvenTree/locale/pl/LC_MESSAGES/django.po +++ b/InvenTree/locale/pl/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:40\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Polish\n" "Language: pl_PL\n" @@ -29,14 +29,14 @@ msgstr "Nie określono działania" msgid "No matching action found" msgstr "Nie znaleziono pasującej akcji" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "Wprowadź dane" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Potwierdź" @@ -72,134 +72,143 @@ msgstr "Zastosuj motyw" msgid "Select Category" msgstr "Wybierz kategorię" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Powtórzony numer seryjny: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "Podano nieprawidłową ilość" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "Pusty ciąg numeru seryjnego" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "Nieprawidłowa grupa: {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "Powtórzony numer seryjny: {g}" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "Nie znaleziono numerów seryjnych" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "Ilość numerów seryjnych ({s}) musi odpowiadać ilości ({q})" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "Załącznik" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "Wybierz plik do załączenia" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Komentarz" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "Komentarz pliku" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Użytkownik" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "data przesłania" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Nazwa" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Opis" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "Opis (opcjonalny)" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "nadrzędny" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "Angielski" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Francuski" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Niemiecki" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Polski" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Turecki" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Nie skonfigurowano backendu e-mail" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Usuń element" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Zaznacz pole aby potwierdzić usunięcie elementu" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Edytuj informacje użytkownika" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Ustaw hasło" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Hasła muszą być zgodne" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Informacja systemowa" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "Data docelowa" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "Ilość" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "Numer seryjny" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "Oznacz budowę jako ukończoną" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "Lokalizacja" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "Lokalizacja ukończonych części" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "Status" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Zlecenie Budowy" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "Zlecenia budowy" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "Odwołanie do zamówienia wykonania" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "Referencja" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "Krótki opis budowy" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "Budowa nadrzędna" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "Zamówienie budowy, do którego budowa jest przypisana" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "Część" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "Wybierz część do budowy" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "Odwołanie do zamówienia sprzedaży" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "Zamówienie sprzedaży, do którego budowa jest przypisana" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "Lokalizacja źródła" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "Wybierz lokalizację, z której pobrać element do budowy (pozostaw puste, aby wziąć z dowolnej lokalizacji)" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "Lokalizacja docelowa" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "Wybierz lokalizację, w której będą przechowywane ukończone elementy" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "Ilość do stworzenia" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "Ilość przedmiotów do zbudowania" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "Ukończone elementy" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "Ilość produktów magazynowych które zostały ukończone" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "Status budowania" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "Kod statusu budowania" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "Kod partii" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "Kod partii dla wyjścia budowy" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "Data utworzenia" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "Docelowy termin zakończenia" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "Data zakończenia" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "zrealizowane przez" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "Wydany przez" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "Użytkownik, który wydał to zamówienie" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "Odpowiedzialny" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "Użytkownik odpowiedzialny za to zamówienie budowy" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "Link Zewnętrzny" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "Link do zewnętrznego adresu URL" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "Uwagi" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "Dodatkowe notatki do budowy" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "Nie określono danych wyjściowych budowy" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "Budowanie wyjścia jest już ukończone" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "Budowa" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "Element magazynowy" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "Lokalizacja magazynowania przedmiotu" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "Zainstaluj do" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "Docelowa lokalizacja magazynowa przedmiotu" @@ -880,7 +885,7 @@ msgstr "Przydziel zapasy do budowy" msgid "Auto Allocate" msgstr "Automatyczne przypisywanie" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "Cofnij przydział zapasów" @@ -894,8 +899,8 @@ msgstr "Zamów wymagane komponenty" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "Zamów części" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "Numer Seryjny" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "Załączniki" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "Edytuj załącznik" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "Usuń załącznik" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "Przydziel automatycznie zapasy" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "Widok administratora" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "Zaległe" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "Postęp" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "Zamówienie zakupu" @@ -1185,7 +1218,10 @@ msgstr "Źródło magazynu" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "Przeznaczenie" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "Nie określono lokalizacji docelowej" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "Partia" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "Utworzony" @@ -1210,7 +1246,7 @@ msgstr "Utworzony" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "Zakończone" @@ -1248,9 +1284,9 @@ msgstr "Szczegóły zlecenia budowy" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "Szczegóły" @@ -1285,8 +1321,7 @@ msgstr "Edytuj uwagi" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "Zapisz" @@ -1315,7 +1350,7 @@ msgstr "Utwórz zlecenie budowy" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "Numer seryjny już istnieje" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "Dostępne" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "Dodano załącznik" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "Edytuj załącznik" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "Załącznik zaktualizowany" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "Usuń załącznik" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "Załącznik usunięto" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "Nazwa firmy" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "Bazowy adres URL dla instancji serwera" #: common/models.py:85 +msgid "Default Currency" +msgstr "" + +#: common/models.py:86 +msgid "Default currency" +msgstr "" + +#: common/models.py:92 msgid "Download from URL" msgstr "Pobierz z adresu URL" -#: common/models.py:86 +#: common/models.py:93 msgid "Allow download of remote images and files from external URL" msgstr "Zezwól na pobieranie zewnętrznych obrazów i plików z zewnętrznego URL" -#: common/models.py:92 +#: common/models.py:99 msgid "Barcode Support" msgstr "Obsługa kodu kreskowego" -#: common/models.py:93 +#: common/models.py:100 msgid "Enable barcode scanner support" msgstr "Włącz obsługę skanera kodów" -#: common/models.py:99 +#: common/models.py:106 msgid "IPN Regex" msgstr "Wyrażenie regularne IPN" -#: common/models.py:100 +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "Zezwól na powtarzający się IPN" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "Zezwól na edycję IPN" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "Skopiuj BOM komponentu" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "Szablon" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "Złożenie" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "Komponent" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "Możliwość zakupu" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "Części są domyślnie z możliwością zakupu" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "Możliwość sprzedaży" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "Części są domyślnie z możliwością sprzedaży" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "Możliwość śledzenia" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "Części są domyślnie z możliwością śledzenia" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "Wirtualny" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "Części są domyślnie wirtualne" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 +#: common/models.py:216 +msgid "Show Import in Views" +msgstr "" + +#: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 msgid "Debug Mode" msgstr "Tryb Debugowania" -#: common/models.py:210 +#: common/models.py:252 msgid "Generate reports in debug mode (HTML output)" msgstr "" -#: common/models.py:216 +#: common/models.py:258 msgid "Page Size" msgstr "Rozmiar strony" -#: common/models.py:217 +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "Raporty testów" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "Włącz generowanie raportów testów" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "dni" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "Grupuj według komponentu" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "Ustawienia wartości" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "Cena" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "Domyślny" @@ -1830,25 +1888,30 @@ msgstr "Domyślny" msgid "Current value" msgstr "Aktualna wartość" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "Zmień ustawienie" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" -msgstr "Wyślik plik" +msgstr "Wyślij plik" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" -msgstr "Waluta" - -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" +msgstr "" + +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "URL" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "URL zdjęcia" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "Cena jednostkowa" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "Cena jednostkowa" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "Wybierz producenta" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "Numer producenta" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "MPN" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "Opis firmy" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "Opis firmy" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "Strona WWW" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "Witryna internetowa firmy" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "Adres" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "Adres firmy" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "Numer telefonu" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "Numer telefonu kontaktowego" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "Adres E-Mail" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "Kontaktowy adres e-mail" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "Kontakt" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "Punkt kontaktowy" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "Łącze" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "Link do informacji o zewnętrznym przedsiębiorstwie" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "Obraz" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "jest klientem" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "Czy sprzedajesz produkty tej firmie?" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "jest dostawcą" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "Czy kupujesz przedmioty od tej firmy?" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "jest producentem" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "Czy to przedsiębiorstwo produkuje części?" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "Waluta" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "Część bazowa" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "Wybierz część" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "Producent" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "Część producenta" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "Jednostki" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "Dostawca" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "Wybierz dostawcę" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "SKU" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "Część producenta" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "Uwaga" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "koszt podstawowy" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "Opakowanie" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "Opakowanie części" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "wielokrotność" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "Firma" @@ -2120,7 +2229,7 @@ msgstr "Prześlij nowy obraz" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "Telefon" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "Nie określono strony internetowej" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "Klient" @@ -2190,7 +2294,8 @@ msgstr "Nowa część producenta" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "Opcje" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "Zamów części" @@ -2212,26 +2317,25 @@ msgstr "Usuń części" msgid "Delete Parts" msgstr "Usuń części" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "Nowy komponent" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "Utwórz nowy komponent" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "Now producent" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "Utwórz nowego producenta" @@ -2241,40 +2345,37 @@ msgstr "Zapasy dostawcy" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "Eksportuj" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "Komponenty dostawcy" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "Utwórz nowego dostawcę części" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "Now dostawca części" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "Nowy dostawca" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "Dodaj nowego dostawcę" @@ -2309,19 +2410,19 @@ msgstr "Szczegóły części producenta" msgid "Internal Part" msgstr "Część wewnętrzna" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "Dostawcy" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "Stan" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "Usuń" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "Parametry" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "Utwórz nowego dostawcę" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "Dostarczone części" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "Informacja cenowa" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "Edytuj przedział cenowy" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "Edytuj przedział cenowy" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "Producenci" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "Klienci" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "Nowy klient" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "Firmy" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "Nowa firma" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "Pobierz obraz" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "Edytuj firmę" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "Utwórz nowego klienta" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "Utwórz nową firmę" - -#: company/views.py:316 -msgid "Created new company" -msgstr "Utwórz nową firmę" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "Usunięto firmę" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "Edytuj przedział cenowy" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "Nazwa etykiety" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "Opis etykiety" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "Etykieta" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "Aktywne" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "Szerokość [mm]" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "Wysokość [mm]" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "Filtry" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "Złóż zamówienie" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "Oznacz zamówienie jako zakończone" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "Anuluj zamówienie" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "Wyślij zamówienie" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "Wprowadź ilość produktów magazynowych" -#: order/models.py:101 -msgid "Order reference" -msgstr "Odniesienie zamówienia" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "Opis Zamówienia" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "Link do zewnętrznej witryny" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "Utworzony przez" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "Użytkownik lub grupa odpowiedzialna za to zamówienie" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "Notatki do zamówienia" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "Odniesienie zamówienia" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "odebrane przez" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "Data wydania" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "Data wysyłki" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "wysłane przez" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "Ilość elementów" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "Zamówienie" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "Odebrane" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "Cena zakupu" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "Cena zakupu jednostkowego" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "Cena sprzedaży" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "Jednostkowa cena sprzedaży" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "Linia" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "Komponent" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "Status zamówienia" msgid "Issued" msgstr "Wydany" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "Nowa lokalizacja" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "Notatki zamówień" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "Wiersz" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "Wybierz dostawcę" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "Usuń część" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "Przedmioty" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "Otrzymane elementy" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "Cena jednostkowa" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "Części" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "Kod zamówienia" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "Odbierz" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "Usuń linie" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "Akcje" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "Numer ID" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "Przydzielono" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "Oblicz cenę" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "Wyślij zamówienie" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "Otrzymane przedmioty" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "Nie ustawiono miejsca docelowego" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "Błąd konwersji ilości na liczbę" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "Nie znaleziono ceny" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "Domyślna lokalizacja" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "Format pliku" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "Wybierz format pliku wyjściowego" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "Kaskadowe" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "Poziomy" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "Część nadrzędna" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "potwierdź" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "Podczęść" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "Domyślne słowa kluczowe" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "Wariant" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "Opis części" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "Słowa kluczowe" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "Kategoria" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "IPN" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "Wersja" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "Minimalny stan magazynowy" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "Jednostki" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "Aktywny" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "Czy ta część jest aktywna?" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "Sprzedaj wiele" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "Nazwa testu" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "Wymagane" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "Dane" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "Wartość domyślna" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "Suma kontrolna" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "Część 1" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "Część 2" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "Wybierz powiązaną część" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "Zestawienie materiałowe" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "Wszystkie części" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "Stwórz nową kategorię komponentów" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "Utwórz nową lokalizację magazynową" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" -msgstr "Parametry" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" +msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "Parametry części" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "Duplikuj część" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "Szczegóły części" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "Edytuj firmę" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/ru/LC_MESSAGES/django.po b/InvenTree/locale/ru/LC_MESSAGES/django.po index d61e19d068..af63aef8e1 100644 --- a/InvenTree/locale/ru/LC_MESSAGES/django.po +++ b/InvenTree/locale/ru/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Russian\n" "Language: ru_RU\n" @@ -29,14 +29,14 @@ msgstr "Действие не указано" msgid "No matching action found" msgstr "Соответствующее действие не найдено" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "Введите дату" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Подтвердить" @@ -72,134 +72,143 @@ msgstr "Применить тему" msgid "Select Category" msgstr "Выбрать категорию" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Дублировать серийный номер: {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "недопустимое количество" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "Пустая строка серийного номера" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "Некорректный идентификатор группы {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "Повторяющийся серийный {g}" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "Серийных номеров не найдено" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "Число уникальных серийных номеров ({s}) должно соответствовать количеству ({q})" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "Вложения" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "Выберите файл для вложения" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Комментарий" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "Комментарий к файлу" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Пользователь" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "дата загрузки" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Название" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Описание" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "Описание (необязательно)" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "родитель" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "Английский" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Французский" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Немецкий" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Польский" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Турецкий" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Проверка фонового работника не удалась" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "Сервер электронной почты не настроен" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "Ошибка проверки состояния системы InvenTree" @@ -372,27 +381,27 @@ msgstr "Перегрузка не может превысить 100%" msgid "Overage must be an integer value or a percentage" msgstr "Превышение должно быть целым числом или процентом" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "Удалить элемент" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "Установите флажок для подтверждения удаления элемента" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "Редактировать информацию о пользователе" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "Установить пароль" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "Пароли должны совпадать" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "Информация о системе" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "Срок выполнения заказа" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "Целевая дата" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "Целевая дата для сборки. Сборка будет просрочена после этой даты." -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "Количество" @@ -500,7 +507,7 @@ msgstr "Количество элементов для сборки" msgid "Enter quantity for build output" msgstr "Введите количество для вывода сборки" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "Серийные номера" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "Пометить сборку как завершенную" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "Расположение" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "Расположение укомплектованных частей" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "Статус" @@ -581,286 +588,284 @@ msgstr "Подтвердите отмену сборки" msgid "Select quantity of stock to allocate" msgstr "Выберите количество запасов для распределения" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "Порядок сборки" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "Порядок сборки" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "Ссылка на заказ" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/tr/LC_MESSAGES/django.po b/InvenTree/locale/tr/LC_MESSAGES/django.po index e30c1ed591..4db90764bd 100644 --- a/InvenTree/locale/tr/LC_MESSAGES/django.po +++ b/InvenTree/locale/tr/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Turkish\n" "Language: tr_TR\n" @@ -19,24 +19,24 @@ msgstr "" #: InvenTree/api.py:64 msgid "API endpoint not found" -msgstr "API uçnoktası bulunmadı" +msgstr "API uç noktası bulunamadı" #: InvenTree/api.py:110 msgid "No action specified" -msgstr "Hiçbir eylem belirtilmedi" +msgstr "İşlem belirtilmedi" #: InvenTree/api.py:124 msgid "No matching action found" msgstr "Eşleşen eylem bulunamadı" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "Tarih giriniz" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "Onay" @@ -72,134 +72,143 @@ msgstr "Temayı Uygula" msgid "Select Category" msgstr "Kategori Seçin" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "Tekrarlanan seri {n}" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "Geçersiz veri sağlandı" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "Boş seri numarası dizesi" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "Geçersiz grup: {g}" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "Tekrarlanan seri {g}" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "Seri numarası bulunamadı" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" -msgstr "Benzersiz serinin numaraları ({s}) miktarla eşleşmeli ({q})" +msgstr "Benzersiz seri numaralarının sayısı ({s}) girilen miktarla eşleşmeli ({q})" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "Ek" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "Eklenecek dosyayı seç" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "Yorum" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" -msgstr "Yorum" +msgstr "Dosya yorumu" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "Kullanıcı" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" -msgstr "Yükleme tarihi" +msgstr "yükleme tarihi" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "Adı" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "Açıklama" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" -msgstr "Açıklama(opsiyonel)" +msgstr "Açıklama (isteğe bağlı)" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" -msgstr "ebeveyn" +msgstr "üst" -#: InvenTree/settings.py:503 +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/settings.py:505 msgid "English" msgstr "İngilizce" -#: InvenTree/settings.py:504 +#: InvenTree/settings.py:506 msgid "French" msgstr "Fransızca" -#: InvenTree/settings.py:505 +#: InvenTree/settings.py:507 msgid "German" msgstr "Almanca" -#: InvenTree/settings.py:506 +#: InvenTree/settings.py:508 msgid "Polish" msgstr "Polonyaca" -#: InvenTree/settings.py:507 +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "Türkçe" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "Arka plan çalışanı kontrolü başarısız oldu" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "E-posta arka ucu yapılandırılmadı" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "InvenTree sistem sağlık kontrolü başarısız" @@ -258,79 +267,79 @@ msgstr "Reddedildi" #: InvenTree/status_codes.py:272 msgid "Legacy stock tracking entry" -msgstr "" +msgstr "Eski stok izleme girişi" #: InvenTree/status_codes.py:274 msgid "Stock item created" -msgstr "" +msgstr "Stok kalemi oluşturuldu" #: InvenTree/status_codes.py:276 msgid "Edited stock item" -msgstr "" +msgstr "Düzenlenen stok kalemi" #: InvenTree/status_codes.py:277 msgid "Assigned serial number" -msgstr "" +msgstr "Atanan seri numarası" #: InvenTree/status_codes.py:279 msgid "Stock counted" -msgstr "" +msgstr "Stok sayıldı" #: InvenTree/status_codes.py:280 msgid "Stock manually added" -msgstr "" +msgstr "Stok manuel olarak eklendi" #: InvenTree/status_codes.py:281 msgid "Stock manually removed" -msgstr "" +msgstr "Stok manuel olarak çıkarıldı" #: InvenTree/status_codes.py:283 msgid "Location changed" -msgstr "" +msgstr "Konum değişti" #: InvenTree/status_codes.py:285 msgid "Installed into assembly" -msgstr "" +msgstr "Montajda kullanıldı" #: InvenTree/status_codes.py:286 msgid "Removed from assembly" -msgstr "" +msgstr "Montajdan çıkarıldı" #: InvenTree/status_codes.py:288 msgid "Installed component item" -msgstr "" +msgstr "Bileşen ögesinde kullanıldı" #: InvenTree/status_codes.py:289 msgid "Removed component item" -msgstr "" +msgstr "Bileşen ögesinden çıkarıldı" #: InvenTree/status_codes.py:291 msgid "Split from parent item" -msgstr "" +msgstr "Üst ögeden ayır" #: InvenTree/status_codes.py:292 msgid "Split child item" -msgstr "" +msgstr "Alt ögeyi ayır" #: InvenTree/status_codes.py:294 templates/js/table_filters.js:181 msgid "Sent to customer" -msgstr "" +msgstr "Müşteriye gönderildi" #: InvenTree/status_codes.py:295 msgid "Returned from customer" -msgstr "" +msgstr "Müşteriden geri döndü" #: InvenTree/status_codes.py:297 msgid "Build order output created" -msgstr "" +msgstr "Yapım emri çıktısı oluşturuldu" #: InvenTree/status_codes.py:298 msgid "Build order output completed" -msgstr "" +msgstr "Yapım emri çıktısı tamamlandı" #: InvenTree/status_codes.py:300 msgid "Received against purchase order" -msgstr "" +msgstr "Satın alma emri karşılığında alındı" #: InvenTree/status_codes.py:315 msgid "Production" @@ -338,11 +347,11 @@ msgstr "Üretim" #: InvenTree/validators.py:22 msgid "Not a valid currency code" -msgstr "Geçerli para birimi yok" +msgstr "Geçerli bir para birimi kodu değil" #: InvenTree/validators.py:50 msgid "Invalid character in part name" -msgstr "Parça adında geçersiniz karakter bulunuyor" +msgstr "Parça adında geçersiz karakter" #: InvenTree/validators.py:63 #, python-brace-format @@ -353,624 +362,649 @@ msgstr "IPN regex kalıbıyla eşleşmelidir {pat}" #: InvenTree/validators.py:105 #, python-brace-format msgid "Reference must match pattern {pattern}" -msgstr "" +msgstr "Referans {pattern} deseniyle mutlaka eşleşmeli" #: InvenTree/validators.py:113 #, python-brace-format msgid "Illegal character in name ({x})" -msgstr "" +msgstr "({x}) adında geçersiz karakter" #: InvenTree/validators.py:132 InvenTree/validators.py:148 msgid "Overage value must not be negative" -msgstr "" +msgstr "Fazlalık değeri negatif olmamalıdır" #: InvenTree/validators.py:150 msgid "Overage must not exceed 100%" -msgstr "" +msgstr "Fazlalık %100'ü geçmemelidir" #: InvenTree/validators.py:157 msgid "Overage must be an integer value or a percentage" -msgstr "" +msgstr "Fazlalık bir tamsayı veya yüzde olmalıdır" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" -msgstr "" +msgstr "Ögeyi Sil" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" -msgstr "" +msgstr "Öge silme işlemini onaylamak için kutuyu işaretleyin" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" -msgstr "" +msgstr "Kullanıcı Bilgisini Düzenle" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" -msgstr "" +msgstr "Şifre Belirle" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" -msgstr "" +msgstr "Parola alanları eşleşmelidir" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" -msgstr "" +msgstr "Sistem Bilgisi" #: barcodes/api.py:53 barcodes/api.py:150 msgid "Must provide barcode_data parameter" -msgstr "" +msgstr "Barcode_data parametresini sağlamalıdır" #: barcodes/api.py:126 msgid "No match found for barcode data" -msgstr "" +msgstr "Barkod verisi için eşleşme bulunamadı" #: barcodes/api.py:128 msgid "Match found for barcode data" -msgstr "" +msgstr "Barkod verisi için eşleşme bulundu" #: barcodes/api.py:153 msgid "Must provide stockitem parameter" -msgstr "" +msgstr "Stok kalemi parametresi sağlamalıdır" #: barcodes/api.py:160 msgid "No matching stock item found" -msgstr "" +msgstr "Eşleşen stok kalemi bulunamadı" #: barcodes/api.py:190 msgid "Barcode already matches StockItem object" -msgstr "" +msgstr "Barkod başka bir stok kalemi nesnesi ile eşleşmektedir" #: barcodes/api.py:194 msgid "Barcode already matches StockLocation object" -msgstr "" +msgstr "Barkod başka bir stok konumu nesnesi ile eşleşmektedir" #: barcodes/api.py:198 msgid "Barcode already matches Part object" -msgstr "" +msgstr "Barkod başka bir parça nesnesi ile eşleşmektedir" #: barcodes/api.py:204 barcodes/api.py:216 msgid "Barcode hash already matches StockItem object" -msgstr "" +msgstr "Barkod karması (hash) zaten stok kalemi nesnesiyle eşleşiyor" #: barcodes/api.py:222 msgid "Barcode associated with StockItem" -msgstr "" +msgstr "Barkod başka bir stok kalemiyle ilişkili" #: build/forms.py:37 msgid "Build Order reference" -msgstr "" +msgstr "Yapım İşi Emri referansı" #: build/forms.py:38 msgid "Order target date" -msgstr "" +msgstr "Emir hedef tarihi" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" -msgstr "" +msgstr "Hedeflenen tarih" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." -msgstr "" +msgstr "Yapım işinin tamamlanması için hedef tarih. Bu tarihten sonra yapım işi gecikmiş olacak." -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" -msgstr "" +msgstr "Miktar" #: build/forms.py:49 msgid "Number of items to build" -msgstr "" +msgstr "Yapılacak öge sayısı" #: build/forms.py:91 msgid "Enter quantity for build output" -msgstr "" +msgstr "Yapım işi çıktısı için miktarını girin" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" -msgstr "" +msgstr "Seri Numaraları" #: build/forms.py:97 msgid "Enter serial numbers for build outputs" -msgstr "" +msgstr "Yapım işi çıktısı için seri numaraları girin" #: build/forms.py:103 msgid "Confirm creation of build output" -msgstr "" +msgstr "Yapım işi çıktısının oluşturulmasını onaylayın" #: build/forms.py:124 msgid "Confirm deletion of build output" -msgstr "" +msgstr "Yapım işi çıktısının silinmesini onaylayın" #: build/forms.py:145 msgid "Confirm unallocation of stock" -msgstr "" +msgstr "Stok tahsisinin iptalini onayla" #: build/forms.py:169 msgid "Confirm stock allocation" -msgstr "" +msgstr "Stok tahsisini onayla" #: build/forms.py:186 msgid "Mark build as complete" -msgstr "" +msgstr "Yapım işini tamamlandı olarak işaretle" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" -msgstr "" +msgstr "Konum" #: build/forms.py:211 msgid "Location of completed parts" -msgstr "" +msgstr "Tamamlanmış parçaların konumu" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" -msgstr "" +msgstr "Durum" #: build/forms.py:216 msgid "Build output stock status" -msgstr "" +msgstr "Yapım işi çıktısı stok durumu" #: build/forms.py:223 msgid "Confirm incomplete" -msgstr "" +msgstr "Eksik olarak onayla" #: build/forms.py:224 msgid "Confirm completion with incomplete stock allocation" -msgstr "" +msgstr "Eksik parça tahsisi ile tamamlamayı onayla" #: build/forms.py:227 msgid "Confirm build completion" -msgstr "" +msgstr "Yapım işinin tamamlandığını onaylayın" #: build/forms.py:252 msgid "Confirm cancel" -msgstr "" +msgstr "İptali Onayla" #: build/forms.py:252 build/views.py:66 msgid "Confirm build cancellation" -msgstr "" +msgstr "Yapım işi iptalini onayla" #: build/forms.py:266 msgid "Select quantity of stock to allocate" -msgstr "" +msgstr "Tahsis edilecek stok miktarını seçiniz" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" -msgstr "" +msgstr "Yapım İşi Emri" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" -msgstr "" +msgstr "Yapım İşi Emirleri" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" -msgstr "" +msgstr "Yapım İşi Emri Referansı" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" -msgstr "" +msgstr "Referans" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" -msgstr "" +msgstr "Yapım işinin kısa açıklaması" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" -msgstr "" +msgstr "Üst Yapım İşi" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" -msgstr "" +msgstr "Bu yapım işinin tahsis edildiği yapım işi emri" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" -msgstr "" +msgstr "Parça" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" -msgstr "" - -#: build/models.py:166 -msgid "Sales Order Reference" -msgstr "" +msgstr "Yapım işi için parça seçin" #: build/models.py:170 -msgid "SalesOrder to which this build is allocated" -msgstr "" +msgid "Sales Order Reference" +msgstr "Satış Emri Referansı" -#: build/models.py:175 -msgid "Source Location" -msgstr "" +#: build/models.py:174 +msgid "SalesOrder to which this build is allocated" +msgstr "Bu yapım işinin tahsis edildiği satış emri" #: build/models.py:179 -msgid "Select location to take stock from for this build (leave blank to take from any stock location)" -msgstr "" +msgid "Source Location" +msgstr "Kaynak Konum" -#: build/models.py:184 -msgid "Destination Location" -msgstr "" +#: build/models.py:183 +msgid "Select location to take stock from for this build (leave blank to take from any stock location)" +msgstr "Bu yapım işi için stok alınacak konumu seçin (her hangi bir stok konumundan alınması için boş bırakın)" #: build/models.py:188 -msgid "Select location where the completed items will be stored" -msgstr "" +msgid "Destination Location" +msgstr "Hedef Konum" #: build/models.py:192 -msgid "Build Quantity" -msgstr "" +msgid "Select location where the completed items will be stored" +msgstr "Tamamlanmış ögelerin saklanacağı konumu seçiniz" -#: build/models.py:195 -msgid "Number of stock items to build" -msgstr "" +#: build/models.py:196 +msgid "Build Quantity" +msgstr "Yapım İşi Miktarı" #: build/models.py:199 +msgid "Number of stock items to build" +msgstr "Yapım işi stok kalemlerinin sayısı" + +#: build/models.py:203 msgid "Completed items" -msgstr "" +msgstr "Tamamlanmış ögeler" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" -msgstr "" +msgstr "Tamamlanan stok kalemlerinin sayısı" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" -msgstr "" +msgstr "Yapım İşi Durumu" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" -msgstr "" +msgstr "Yapım işi durum kodu" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" -msgstr "" +msgstr "Sıra numarası" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" -msgstr "" +msgstr "Yapım işi çıktısı için sıra numarası" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" -msgstr "" +msgstr "Oluşturulma tarihi" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" -msgstr "" +msgstr "Hedef tamamlama tarihi" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" -msgstr "" +msgstr "Tamamlama tarihi" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" -msgstr "" +msgstr "tamamlayan" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" -msgstr "" +msgstr "Veren" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" -msgstr "" +msgstr "Bu yapım işi emrini veren kullanıcı" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" -msgstr "" +msgstr "Sorumlu" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" -msgstr "" +msgstr "Bu yapım işi emrinden sorumlu kullanıcı" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" -msgstr "" +msgstr "Harici Bağlantı" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" -msgstr "" +msgstr "Harici URL'ye bağlantı" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" -msgstr "" +msgstr "Notlar" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" -msgstr "" +msgstr "Yapım işi için ekstra notlar" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" -msgstr "" +msgstr "Yapım işi çıktısı belirtilmedi" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" -msgstr "" +msgstr "Yapım işi çıktısı zaten tamamlanmış" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" -msgstr "" +msgstr "Yapım işi çıktısı, yapım işi emri ile eşleşmiyor" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" -msgstr "" +msgstr "Yapım işi ögesi; yapım işi, stok kalemi ve kurulacak yer için benzersiz olmalıdır" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" -msgstr "" +msgstr "Ana parça izlenebilir olarak işaretlendiğinden, yapım işi çıktısı için bir yapım işi ögesi belirtmelidir" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" -msgstr "" +msgstr "Tahsis edilecek miktar ({n}) mevcut miktarı ({q}) geçmemeli" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" -msgstr "" +msgstr "Stok kalemi fazladan tahsis edilmiş" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" -msgstr "" +msgstr "Tahsis edilen miktar sıfırdan büyük olmalıdır" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" -msgstr "" +msgstr "Seri numaralı stok için miktar bir olmalı" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" -msgstr "" +msgstr "{p} parçasının malzeme listesindeki seçili stok kalemi bulunamadı" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" -msgstr "" +msgstr "Yapım İşi" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" -msgstr "" +msgstr "Yapım işi için tahsis edilen parçalar" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" -msgstr "" +msgstr "Stok Kalemi" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" -msgstr "" - -#: build/models.py:1347 -msgid "Stock quantity to allocate to build" -msgstr "" +msgstr "Kaynak stok kalemi" #: build/models.py:1355 -msgid "Install into" -msgstr "" +msgid "Stock quantity to allocate to build" +msgstr "Yapım işi için tahsis edilen stok miktarı" -#: build/models.py:1356 +#: build/models.py:1363 +msgid "Install into" +msgstr "Kurulduğu yer" + +#: build/models.py:1364 msgid "Destination stock item" -msgstr "" +msgstr "Hedef stok kalemi" #: build/templates/build/allocate.html:7 msgid "Allocate Parts" -msgstr "" +msgstr "Parçaları Tahsis Et" #: build/templates/build/allocate.html:15 msgid "Allocate Stock to Build" -msgstr "" +msgstr "Yapım İşi için Stok Tahsis Et" #: build/templates/build/allocate.html:22 msgid "Allocate stock to build" -msgstr "" +msgstr "Yapım işi için stok tahsis et" #: build/templates/build/allocate.html:23 msgid "Auto Allocate" -msgstr "" +msgstr "Otomatik Tahsis Et" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" -msgstr "" +msgstr "Stok tahsisini kaldır" #: build/templates/build/allocate.html:26 build/views.py:319 build/views.py:805 msgid "Unallocate Stock" -msgstr "" +msgstr "Stok Tahsisini Kaldır" #: build/templates/build/allocate.html:29 msgid "Order required parts" -msgstr "" +msgstr "Gerekli parçaları sipariş edin" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" -msgstr "" +msgstr "Parça Siparişi" #: build/templates/build/allocate.html:36 msgid "Untracked stock has been fully allocated for this Build Order" -msgstr "" +msgstr "Takip edilmeyen stok yapım işi emri için tamamen tahsis edildi" #: build/templates/build/allocate.html:40 msgid "Untracked stock has not been fully allocated for this Build Order" -msgstr "" +msgstr "Takip edilmeyen stok yapım işi emri için tamamen tahsis edilemedi" #: build/templates/build/allocate.html:47 msgid "This Build Order does not have any associated untracked BOM items" -msgstr "" +msgstr "Bu yapım işi emri, herhangi bir takip edilmeyen malzeme listesi öğesine sahip değil" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" -msgstr "" +msgstr "Seri Numara" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" +msgstr "Ekler" + +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" msgstr "" +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "Ek Düzenle" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "Eki Sil" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" -msgstr "" +msgstr "Stoku Otomatik Olarak Tahsis Et" #: build/templates/build/auto_allocate.html:10 msgid "The following stock items will be allocated to the specified build output" -msgstr "" +msgstr "Aşağıdaki stok kalemleri, belirtilen yapım işi çıktısı için tahsis edilecek" #: build/templates/build/auto_allocate.html:37 msgid "No stock items found that can be automatically allocated to this build" -msgstr "" +msgstr "Bu yapım işi için otomatik tahsis edilecek stok kalemleri bulunamadı" #: build/templates/build/auto_allocate.html:39 msgid "Stock items will have to be manually allocated" -msgstr "" +msgstr "Stok kalemleri manuel olarak tahsis edilecek" #: build/templates/build/build_base.html:18 #, python-format msgid "This Build Order is allocated to Sales Order %(link)s" -msgstr "" +msgstr "Bu yapım işi emri, %(link)s sipariş emrine tahsis edilmiştir" #: build/templates/build/build_base.html:25 #, python-format msgid "This Build Order is a child of Build Order %(link)s" -msgstr "" +msgstr "Bu yapım işi emri, %(link)s yapım iş emrinin altıdır" #: build/templates/build/build_base.html:32 msgid "Build Order is ready to mark as completed" -msgstr "" +msgstr "Yapım işi tamamlandı olarak işaretlenmeye hazır" #: build/templates/build/build_base.html:37 msgid "Build Order cannot be completed as outstanding outputs remain" -msgstr "" +msgstr "Bekleyen çıktılar kaldığı için yapım işi emri tamamlanamıyor" #: build/templates/build/build_base.html:42 msgid "Required build quantity has not yet been completed" -msgstr "" +msgstr "Gerekli yapım işi miktarı henüz tamamlanmadı" #: build/templates/build/build_base.html:47 msgid "Stock has not been fully allocated to this Build Order" -msgstr "" +msgstr "Stok, yapım işi emri için tamamen tahsis edilemedi" #: build/templates/build/build_base.html:75 #: company/templates/company/company_base.html:40 @@ -978,11 +1012,11 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" -msgstr "" +msgstr "Yönetici görünümü" #: build/templates/build/build_base.html:81 #: build/templates/build/build_base.html:150 @@ -990,118 +1024,117 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" -msgstr "" +msgstr "Vadesi geçmiş" #: build/templates/build/build_base.html:90 msgid "Print actions" -msgstr "" +msgstr "Yazdırma işlemleri" #: build/templates/build/build_base.html:94 msgid "Print Build Order" -msgstr "" +msgstr "Yapım İşi Emrini Yazdır" #: build/templates/build/build_base.html:100 #: build/templates/build/build_base.html:225 msgid "Complete Build" -msgstr "" +msgstr "Tamamlanmış Yapım İşi" #: build/templates/build/build_base.html:105 msgid "Build actions" -msgstr "" +msgstr "Yapım İşi işlemleri" #: build/templates/build/build_base.html:109 msgid "Edit Build" -msgstr "" +msgstr "Yapım İşini Düzenle" #: build/templates/build/build_base.html:111 #: build/templates/build/build_base.html:209 build/views.py:57 msgid "Cancel Build" -msgstr "" +msgstr "Yapım İşini İptal Et" #: build/templates/build/build_base.html:124 #: build/templates/build/detail.html:11 msgid "Build Details" -msgstr "" +msgstr "Yapım İşi Detayları" #: build/templates/build/build_base.html:150 #, python-format msgid "This build was due on %(target)s" -msgstr "" +msgstr "Bu yapım işinin %(target)s tarihinde süresi doluyor" #: build/templates/build/build_base.html:157 #: build/templates/build/detail.html:64 msgid "Progress" -msgstr "" +msgstr "İlerleme" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" -msgstr "" +msgstr "Sipariş Emri" #: build/templates/build/build_base.html:177 #: build/templates/build/detail.html:98 #: report/templates/report/inventree_build_order_base.html:153 msgid "Issued By" -msgstr "" +msgstr "Veren" #: build/templates/build/build_base.html:217 msgid "Incomplete Outputs" -msgstr "" +msgstr "Tamamlanmamış Çıktılar" #: build/templates/build/build_base.html:218 msgid "Build Order cannot be completed as incomplete build outputs remain" -msgstr "" +msgstr "Tamamlanmamış yapım işi çıktıları kaldığı için yapım işi emri tamamlanamıyor" #: build/templates/build/build_children.html:10 #: build/templates/build/navbar.html:36 msgid "Child Build Orders" -msgstr "" +msgstr "Alt Yapım İşi Emrileri" #: build/templates/build/build_output.html:15 msgid "Incomplete Build Outputs" -msgstr "" +msgstr "Tamamlanmamış Yapım İşi Çıktıları" #: build/templates/build/build_output.html:22 msgid "Create new build output" -msgstr "" +msgstr "Yeni yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:23 msgid "Create New Output" -msgstr "" +msgstr "Yeni Çıktı Oluştur" #: build/templates/build/build_output.html:36 msgid "Create a new build output" -msgstr "" +msgstr "Yeni bir yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:37 msgid "No incomplete build outputs remain." -msgstr "" +msgstr "Tamamlanmamış yapım işi çıktısı kalmadı." #: build/templates/build/build_output.html:38 msgid "Create a new build output using the button above" -msgstr "" +msgstr "Yukarıdaki düğmeyi kullanarak yeni bir yapım işi çıktısı oluştur" #: build/templates/build/build_output.html:49 msgid "Completed Build Outputs" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Çıktıları" #: build/templates/build/build_output_create.html:7 msgid "The Bill of Materials contains trackable parts" -msgstr "" +msgstr "Bu Malzeme Listesi takip edilebilir parçalar içeriyor" #: build/templates/build/build_output_create.html:8 msgid "Build outputs must be generated individually." -msgstr "" +msgstr "Yapım işi çıktıları ayrı ayrı oluşturulmalıdır." #: build/templates/build/build_output_create.html:9 msgid "Multiple build outputs will be created based on the quantity specified." @@ -1109,11 +1142,11 @@ msgstr "" #: build/templates/build/build_output_create.html:15 msgid "Trackable parts can have serial numbers specified" -msgstr "" +msgstr "Takip edilebilir parçaların seri numaraları belirtilmiş olmalı" #: build/templates/build/build_output_create.html:16 msgid "Enter serial numbers to generate multiple single build outputs" -msgstr "" +msgstr "Birden çok tek yapım işi çıktısı oluşturmak için seri numaraları girin" #: build/templates/build/cancel.html:5 msgid "Are you sure you wish to cancel this build?" @@ -1121,370 +1154,347 @@ msgstr "" #: build/templates/build/complete.html:8 msgid "Build Order is complete" -msgstr "" +msgstr "Yapım işi emri tamamlandı" #: build/templates/build/complete.html:12 msgid "Build Order is incomplete" -msgstr "" +msgstr "Yapım işi emri eksik" #: build/templates/build/complete.html:15 msgid "Incompleted build outputs remain" -msgstr "" +msgstr "Eksik yapım işi çıktıları kaldı" #: build/templates/build/complete.html:18 msgid "Required build quantity has not been completed" -msgstr "" +msgstr "Gerekli yapım işi miktarı tamamlanmadı" #: build/templates/build/complete.html:21 msgid "Required stock has not been fully allocated" -msgstr "" +msgstr "Gerekli stok tamamen tahsis edilemedi" #: build/templates/build/complete_output.html:10 msgid "Stock allocation is complete for this output" -msgstr "" +msgstr "Bu çıktı için stok tahsisi tamamlandı" #: build/templates/build/complete_output.html:14 msgid "Stock allocation is incomplete" -msgstr "" +msgstr "Stok tahsisi tamamlanmamış" #: build/templates/build/complete_output.html:20 msgid "tracked parts have not been fully allocated" -msgstr "" +msgstr "takip edilebilir parçalar tamamen tahsis edilemedi" #: build/templates/build/complete_output.html:41 msgid "The following items will be created" -msgstr "" +msgstr "Aşağıdaki ögeler oluşturulacak" #: build/templates/build/create_build_item.html:7 msgid "Select a stock item to allocate to the selected build output" -msgstr "" +msgstr "Seçili yapım işi emri için tahsis edilecek bir stok kalemi seçiniz" #: build/templates/build/create_build_item.html:11 #, python-format msgid "The allocated stock will be installed into the following build output:
                %(output)s" -msgstr "" +msgstr "Tahsis edilen stok bu yapım işi çıktısının kurulmasında kullanılacak:
                %(output)s" #: build/templates/build/create_build_item.html:17 #, python-format msgid "No stock available for %(part)s" -msgstr "" +msgstr "%(part)s için mevcut stok yok" #: build/templates/build/delete_build_item.html:8 msgid "Are you sure you want to unallocate this stock?" -msgstr "" +msgstr "Bu stokun tahsisinin iptal etmek istediğinizden emin misiniz?" #: build/templates/build/delete_build_item.html:11 msgid "The selected stock will be unallocated from the build output" -msgstr "" +msgstr "Bu yapım işi için seçili stok tahsisi iptal edilecek" #: build/templates/build/detail.html:35 msgid "Stock Source" -msgstr "" +msgstr "Stok Kaynağı" #: build/templates/build/detail.html:40 msgid "Stock can be taken from any available location." -msgstr "" +msgstr "Stok herhangi bir konumdan alınabilir." -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" -msgstr "" +msgstr "Hedef" #: build/templates/build/detail.html:53 msgid "Destination location not specified" -msgstr "" +msgstr "Hedef konumu belirtilmedi" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" -msgstr "" +msgstr "Toplu" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" -msgstr "" +msgstr "Oluşturuldu" #: build/templates/build/detail.html:127 msgid "No target date set" -msgstr "" +msgstr "Hedef tarih ayarlanmadı" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" -msgstr "" +msgstr "Tamamlandı" #: build/templates/build/detail.html:136 msgid "Build not complete" -msgstr "" +msgstr "Yapım İşi tamamlanmadı" #: build/templates/build/edit_build_item.html:7 msgid "Alter the quantity of stock allocated to the build output" -msgstr "" +msgstr "Yapım işi çıktısına tahsis edilen stok miktarını değiştir" #: build/templates/build/index.html:28 build/views.py:678 msgid "New Build Order" -msgstr "" +msgstr "Yeni Yapım İşi Emri" #: build/templates/build/index.html:37 build/templates/build/index.html:38 msgid "Print Build Orders" -msgstr "" +msgstr "Yapım İşi Emirlerini Yazdır" #: build/templates/build/index.html:43 #: order/templates/order/purchase_orders.html:27 #: order/templates/order/sales_orders.html:27 msgid "Display calendar view" -msgstr "" +msgstr "Takvim görünümünü görüntüle" #: build/templates/build/index.html:46 #: order/templates/order/purchase_orders.html:30 #: order/templates/order/sales_orders.html:30 msgid "Display list view" -msgstr "" +msgstr "Liste görünümünü görüntüle" #: build/templates/build/navbar.html:12 msgid "Build Order Details" -msgstr "" +msgstr "Yapım İşi Emri Detayları" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" -msgstr "" +msgstr "Detaylar" #: build/templates/build/navbar.html:21 build/templates/build/navbar.html:24 #: build/views.py:91 msgid "Allocate Stock" -msgstr "" +msgstr "Stok Tahsis Et" #: build/templates/build/navbar.html:29 build/templates/build/navbar.html:32 msgid "Build Outputs" -msgstr "" +msgstr "Yapım İşi Çıktıları" #: build/templates/build/navbar.html:39 msgid "Child Builds" -msgstr "" +msgstr "Alt Yapım İşleri" #: build/templates/build/navbar.html:50 msgid "Build Order Notes" -msgstr "" +msgstr "Yapım İşi Emri Notları" #: build/templates/build/notes.html:12 msgid "Build Notes" -msgstr "" +msgstr "Yapım İşi Notları" #: build/templates/build/notes.html:14 company/templates/company/notes.html:13 #: order/templates/order/order_notes.html:15 #: order/templates/order/sales_order_notes.html:16 #: part/templates/part/notes.html:14 stock/templates/stock/item_notes.html:15 msgid "Edit notes" -msgstr "" +msgstr "Notları Düzenle" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" -msgstr "" +msgstr "Kaydet" #: build/templates/build/unallocate.html:10 msgid "Are you sure you wish to unallocate all stock for this build?" -msgstr "" +msgstr "Bu yapım işi için tahsis edilen tüm stokları kaldırmak istediğinizden emin misiniz?" #: build/templates/build/unallocate.html:12 msgid "All incomplete stock allocations will be removed from the build" -msgstr "" +msgstr "Tüm eksik stok tahsisleri yapım işinden kaldırılacak" #: build/views.py:77 msgid "Build was cancelled" -msgstr "" +msgstr "Yapım işi iptal edildi" #: build/views.py:138 msgid "Allocated stock to build output" -msgstr "" +msgstr "Yapım işi çıktısına stok tahsis edildi" #: build/views.py:150 msgid "Create Build Output" -msgstr "" +msgstr "Yapım İşi Çıktısı Oluştur" #: build/views.py:168 msgid "Maximum output quantity is " -msgstr "" +msgstr "Maksimum çıktı miktarı " -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" -msgstr "" +msgstr "Seri numaraları zaten mevcut" #: build/views.py:193 msgid "Serial numbers required for trackable build output" -msgstr "" +msgstr "Seri numaraları takip edilebilir yapım işi çıktıları için gerekli" #: build/views.py:259 msgid "Delete Build Output" -msgstr "" +msgstr "Yapım İşi Çıktısı Sil" #: build/views.py:280 build/views.py:370 msgid "Confirm unallocation of build stock" -msgstr "" +msgstr "Yapım işi stoku tahsisinin iptalini onayla" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" -msgstr "" +msgstr "Onay kutusunu işaretleyin" #: build/views.py:293 msgid "Build output does not match build" -msgstr "" +msgstr "Yapım işi çıktısı yapım işi ile eşleşmiyor" #: build/views.py:295 build/views.py:496 msgid "Build output must be specified" -msgstr "" +msgstr "Yapım işi çıktısı belirtilmeli" #: build/views.py:307 msgid "Build output deleted" -msgstr "" +msgstr "Yapım işi çıktısı silindi" #: build/views.py:405 msgid "Complete Build Order" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Emri" #: build/views.py:411 msgid "Build order cannot be completed - incomplete outputs remain" -msgstr "" +msgstr "Yapım işi emri tamamlanamadı - eksik çıktılar kaldı" #: build/views.py:422 msgid "Completed build order" -msgstr "" +msgstr "Tamamlanmış yapım işi emri" #: build/views.py:438 msgid "Complete Build Output" -msgstr "" +msgstr "Tamamlanmış Yapım İşi Çıktısı" #: build/views.py:480 msgid "Invalid stock status value selected" -msgstr "" +msgstr "Geçersiz stok durum değeri seçildi" #: build/views.py:487 msgid "Quantity to complete cannot exceed build output quantity" -msgstr "" +msgstr "Tamamlanacak miktar yapım işi çıktı miktarını aşamaz" #: build/views.py:493 msgid "Confirm completion of incomplete build" -msgstr "" +msgstr "Eksik yapım işinin tamamlandığını onaylayın" #: build/views.py:592 msgid "Build output completed" -msgstr "" +msgstr "Yapım işi çıktısı tamamlandı" #: build/views.py:732 msgid "Created new build" -msgstr "" +msgstr "Yeni yapım işi oluşturuldu" #: build/views.py:753 msgid "Edit Build Order Details" -msgstr "" +msgstr "Yapım İşi Emri Detaylarını Düzenle" #: build/views.py:786 msgid "Edited build" -msgstr "" +msgstr "Yapım işi düzenlendi" #: build/views.py:795 msgid "Delete Build Order" -msgstr "" +msgstr "Yapım İşi Emrini Sil" #: build/views.py:810 msgid "Removed parts from build allocation" -msgstr "" +msgstr "Yapım işinden tahsis edilen parçalar çıkarıldı" #: build/views.py:822 msgid "Allocate stock to build output" -msgstr "" +msgstr "Yapım işi çıktısına stok tahsis edildi" #: build/views.py:865 msgid "Item must be currently in stock" -msgstr "" +msgstr "Öge stokta bulunmalı" #: build/views.py:871 msgid "Stock item is over-allocated" -msgstr "" +msgstr "Stok kalemi fazladan tahsis edilmiş" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" -msgstr "" +msgstr "Mevcut" #: build/views.py:874 msgid "Stock item must be selected" -msgstr "" +msgstr "Stok kalemi seçilmeli" #: build/views.py:1037 msgid "Edit Stock Allocation" -msgstr "" +msgstr "Stok Tahsisini Düzenle" #: build/views.py:1041 msgid "Updated Build Item" -msgstr "" +msgstr "Yapım İşi Ögesini Güncelle" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" -msgstr "" - -#: common/files.py:69 -msgid "Error reading file (invalid format)" -msgstr "" +msgstr "Desteklenmeyen dosya formatı: {ext.upper()}" #: common/files.py:71 -msgid "Error reading file (incorrect dimension)" -msgstr "" +msgid "Error reading file (invalid format)" +msgstr "Dosya okurken hata (geçersiz biçim)" #: common/files.py:73 +msgid "Error reading file (incorrect dimension)" +msgstr "Dosya okurken hata (hatalı ölçüler)" + +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" -msgstr "" +msgstr "Dosya okurken hata (veri bozulmuş olabilir)" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" -msgstr "" +msgstr "Dosya" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" -msgstr "" +msgstr "Yüklenecek dosyayı seç" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" -msgstr "" +msgstr "{name.title()} Dosya" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" -msgstr "" +msgstr "{name} dosyasını yüklemek için seçin" #: common/models.py:59 msgid "InvenTree Instance Name" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" -msgstr "" +msgid "Allow download of remote images and files from external URL" +msgstr "Harici URL'den resim ve dosyaların indirilmesine izin ver" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "DPN Regex" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" -msgstr "" - -#: common/models.py:104 -msgid "Allow Duplicate IPN" -msgstr "" - -#: common/models.py:105 -msgid "Allow multiple parts to share the same IPN" -msgstr "" +msgstr "Parça DPN eşleştirmesi için Düzenli İfade Kalıbı (Regex)" #: common/models.py:111 -msgid "Allow Editing IPN" -msgstr "" +msgid "Allow Duplicate IPN" +msgstr "Yinelenen DPN'ye İzin Ver" #: common/models.py:112 -msgid "Allow changing the IPN value while editing a part" -msgstr "" +msgid "Allow multiple parts to share the same IPN" +msgstr "Birden çok parçanın aynı DPN'yi paylaşmasına izin ver" #: common/models.py:118 +msgid "Allow Editing IPN" +msgstr "DPN Düzenlemeye İzin Ver" + +#: common/models.py:119 +msgid "Allow changing the IPN value while editing a part" +msgstr "Parçayı düzenlerken DPN değiştirmeye izin ver" + +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 -msgid "Copy Category Parameter Templates" -msgstr "" - -#: common/models.py:140 -msgid "Copy category parameter templates when creating a part" -msgstr "" - #: common/models.py:146 +msgid "Copy Category Parameter Templates" +msgstr "Kategori Paremetre Sablonu Kopyala" + +#: common/models.py:147 +msgid "Copy category parameter templates when creating a part" +msgstr "Parça oluştururken kategori parametre şablonlarını kopyala" + +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" -msgstr "" - -#: common/models.py:154 -msgid "Parts are templates by default" -msgstr "" - -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 -msgid "Assembly" -msgstr "" +msgstr "Şablon" #: common/models.py:161 -msgid "Parts can be assembled from other components by default" -msgstr "" +msgid "Parts are templates by default" +msgstr "Parçaları varsayılan olan şablondur" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 -msgid "Component" -msgstr "" +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 +msgid "Assembly" +msgstr "Montaj" #: common/models.py:168 -msgid "Parts can be used as sub-components by default" -msgstr "" +msgid "Parts can be assembled from other components by default" +msgstr "Parçalar varsayılan olarak başka bileşenlerden monte edilebilir" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 -msgid "Purchaseable" -msgstr "" +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 +msgid "Component" +msgstr "Bileşen" #: common/models.py:175 -msgid "Parts are purchaseable by default" -msgstr "" +msgid "Parts can be used as sub-components by default" +msgstr "Parçalar varsayılan olarak alt bileşen olarak kullanılabilir" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 -msgid "Salable" -msgstr "" +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 +msgid "Purchaseable" +msgstr "Satın Alınabilir" #: common/models.py:182 -msgid "Parts are salable by default" -msgstr "" +msgid "Parts are purchaseable by default" +msgstr "Parçalar varsayılan olarak satın alınabilir" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 -msgid "Trackable" -msgstr "" +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 +msgid "Salable" +msgstr "Satılabilir" #: common/models.py:189 -msgid "Parts are trackable by default" -msgstr "" +msgid "Parts are salable by default" +msgstr "Parçalar varsayılan olarak satılabilir" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 -#: templates/js/table_filters.js:29 -msgid "Virtual" -msgstr "" +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 +msgid "Trackable" +msgstr "Takip Edilebilir" #: common/models.py:196 -msgid "Parts are virtual by default" -msgstr "" +msgid "Parts are trackable by default" +msgstr "Parçalar varsayılan olarak takip edilebilir" -#: common/models.py:202 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 +#: templates/js/table_filters.js:29 +msgid "Virtual" +msgstr "Sanal" + +#: common/models.py:203 +msgid "Parts are virtual by default" +msgstr "Parçalar varsayılan olarak sanaldır" + +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" -msgstr "" +msgstr "Stok konumu ve ögeler üzerinde sahiplik kontrolünü etkinleştirin" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" -msgstr "" +msgstr "Dosya Yükle" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" -msgstr "" +msgstr "Atanan Stok" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,15 +2229,16 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" -msgstr "" +msgstr "Satın Alma Emri Oluştur" #: company/templates/company/company_base.html:51 msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,13 +2269,13 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" -msgstr "" +msgstr "Müşteri" #: company/templates/company/detail_manufacturer_part.html:11 #: templates/InvenTree/search.html:149 @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,83 +2303,79 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" #: company/templates/company/detail_manufacturer_part.html:36 #: company/templates/company/detail_supplier_part.html:35 msgid "Delete parts" -msgstr "" +msgstr "Parçaları sil" #: company/templates/company/detail_manufacturer_part.html:36 #: company/templates/company/detail_supplier_part.html:35 msgid "Delete Parts" -msgstr "" +msgstr "Parçaları Sil" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" #: company/templates/company/detail_stock.html:10 msgid "Supplier Stock" -msgstr "" +msgstr "Tedarikçi Stoku" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" -msgstr "" +msgstr "Tedarikçi Parçaları" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" -msgstr "" +msgstr "Yeni tedarikçi parçası oluştur" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" -msgstr "" +msgstr "Yeni Tedarikçi Parçası" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2287,7 +2388,7 @@ msgstr "" #: company/templates/company/supplier_part_orders.html:17 #: part/templates/part/orders.html:17 part/templates/part/part_base.html:58 msgid "Order part" -msgstr "" +msgstr "Parça siparişi" #: company/templates/company/manufacturer_part_base.html:41 msgid "Edit manufacturer part" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,16 +2433,16 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" -msgstr "" +msgstr "Stok" #: company/templates/company/manufacturer_part_navbar.html:26 msgid "Manufacturer Part Orders" @@ -2355,20 +2456,52 @@ msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 #: part/templates/part/supplier.html:22 msgid "Delete supplier parts" -msgstr "" +msgstr "Tedarikçi parçalarını sil" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,16 +2512,16 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" -msgstr "" +msgstr "Stok Kalemleri" #: company/templates/company/navbar.html:47 #: company/templates/company/navbar.html:56 @@ -2396,25 +2529,25 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" -msgstr "" +msgstr "Satış Emirleri" #: company/templates/company/navbar.html:50 #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" -msgstr "" +msgstr "Satın Alma Emirleri" #: company/templates/company/notes.html:11 msgid "Company Notes" @@ -2423,59 +2556,60 @@ msgstr "" #: company/templates/company/purchase_orders.html:18 #: order/templates/order/purchase_orders.html:20 msgid "Create new purchase order" -msgstr "" +msgstr "Yeni satın alma emri oluştur" #: company/templates/company/purchase_orders.html:19 #: order/templates/order/purchase_orders.html:21 msgid "New Purchase Order" -msgstr "" +msgstr "Yeni Satın Alma Emri" #: company/templates/company/sales_orders.html:19 #: order/templates/order/sales_orders.html:20 msgid "Create new sales order" -msgstr "" +msgstr "Yeni satış emri oluştur" #: company/templates/company/sales_orders.html:20 #: order/templates/order/sales_orders.html:21 msgid "New Sales Order" -msgstr "" +msgstr "Yeni Satış Emri" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" -msgstr "" +msgstr "Tedarikçi Parçası" #: company/templates/company/supplier_part_base.html:40 msgid "Edit supplier part" -msgstr "" +msgstr "Tedarikçi parçasını düzenle" #: company/templates/company/supplier_part_base.html:44 msgid "Delete supplier part" -msgstr "" +msgstr "Tedarikçi parçasını sil" #: company/templates/company/supplier_part_base.html:56 #: company/templates/company/supplier_part_detail.html:10 msgid "Supplier Part Details" -msgstr "" +msgstr "Tedarikçi Parçası Detayları" #: company/templates/company/supplier_part_delete.html:5 msgid "Are you sure you want to delete the following Supplier Parts?" -msgstr "" +msgstr "Aşağıdaki Tedarikçi Parçalarını silmek istediğinizden emin misin?" #: company/templates/company/supplier_part_navbar.html:12 #: company/templates/company/supplier_part_stock.html:10 msgid "Supplier Part Stock" -msgstr "" +msgstr "Tedarikçi Parça Stoku" #: company/templates/company/supplier_part_navbar.html:19 #: company/templates/company/supplier_part_orders.html:10 msgid "Supplier Part Orders" -msgstr "" +msgstr "Tedarikçi Parçası Emirleri" #: company/templates/company/supplier_part_navbar.html:26 msgid "Supplier Part Pricing" -msgstr "" +msgstr "Tedarikçi Parçası Fiyatlandırması" #: company/templates/company/supplier_part_navbar.html:29 msgid "Pricing" @@ -2487,447 +2621,399 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" -msgstr "" +msgstr "Sağlanan URL geçerli bir resim dosyası değil" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" -msgstr "" +msgstr "Şablon için geçerli bir nesne sağlanmadı" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" -msgstr "" +msgstr "Etiket adı" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" -msgstr "" +msgstr "Etiket tanımı" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" -msgstr "" +msgstr "Etiket" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" -msgstr "" +msgstr "Etiket şablon listesi" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" -msgstr "" +msgstr "Etiket sablonu etkinleştirildi" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" -msgstr "" +msgstr "Etiket genişliği mm olarak belirtilmeli" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" -msgstr "" +msgstr "Etiket yüksekliği mm olarak belirtilmeli" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" -msgstr "" +msgstr "Dosya Adı Deseni" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" -msgstr "" +msgstr "Etiket dosya adları oluşturma için desen" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" -msgstr "" +msgstr "Parçaları bu konuma alın" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" -msgstr "" +msgstr "Stok kalemi seri numaları girin" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" -msgstr "" +msgstr "Tahsis miktarı stok miktarını aşamaz" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" -msgstr "" +msgstr "Seri numaralı stok kalemi için miktar bir olmalı" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" +msgstr "Stok tahsis miktarını girin" + +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" msgstr "" #: order/templates/order/delete_attachment.html:5 @@ -2952,10 +3038,10 @@ msgstr "" #: order/templates/order/order_base.html:64 msgid "Export order to file" -msgstr "" +msgstr "Emiri dosya çıkar" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,19 +3060,25 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 -msgid "New Location" +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 +msgid "New Location" +msgstr "Yeni Konum" + +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" -msgstr "" +msgstr "Yeni stok konumu oluştur" #: order/templates/order/order_cancel.html:8 msgid "Cancelling this order means that the order and line items will no longer be editable." @@ -3014,65 +3106,81 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" -msgstr "" +msgstr "Aşağıdaki gerekli sütunlar için eksik seçimler" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" -msgstr "" +msgstr "Dosya Alanları" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" -msgstr "" +msgstr "Tedarikçi Parçası Seçin" #: order/templates/order/order_wizard/po_upload.html:11 msgid "Upload File for Purchase Order" -msgstr "" +msgstr "Sipariş Emri için Dosya Yükle" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" -msgstr "" +msgstr "Adım 1/2 - Parça Tedarikçileri Seçin" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,17 +3329,17 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" -msgstr "" +msgstr "Parçalar" #: order/templates/order/receive_parts.html:15 msgid "Select parts to receive against this order" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,16 +3379,20 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 #: stock/templates/stock/stockitem_convert.html:13 msgid "Warning" -msgstr "" +msgstr "Uyarı" #: order/templates/order/sales_order_cancel.html:9 msgid "Cancelling this order means that the order will no longer be editable." @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" -msgstr "" +msgstr "İşlemler" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" -msgstr "" +msgstr "Stok tahsisini düzenle" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" -msgstr "" +msgstr "Stok tahsisini sil" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" -msgstr "" +msgstr "Seri numaralarını tahsis et" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3340,7 +3478,7 @@ msgstr "" #: order/templates/order/sales_order_ship.html:12 msgid "Ensure that the order allocation is correct before shipping the order." -msgstr "" +msgstr "Emri göndermeden önce emir tahsisinin doğru olduğundan emin olun." #: order/templates/order/sales_order_ship.html:18 msgid "Some line items in this order have been over-allocated" @@ -3356,208 +3494,168 @@ msgstr "" #: order/templates/order/so_allocate_by_serial.html:9 msgid "Allocate stock items by serial number" -msgstr "" +msgstr "Seri numarası ile stok kalemlerini tahsis et" #: order/templates/order/so_allocation_delete.html:7 msgid "This action will unallocate the following stock from the Sales Order" -msgstr "" +msgstr "Bu işlem Sipariş Emrinden belirtilen stok kalemleri tahsis edemedi" #: order/templates/order/so_attachments.html:12 #: order/templates/order/so_navbar.html:26 msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" -msgstr "" +msgstr "Seri Numaralarını Tahsis Et" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" -msgstr "" +msgstr "{serial} seri numarası için eşleşen öge bulunamadı" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" -msgstr "" +msgstr "{serial} stokta yok" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" -msgstr "" +msgstr "{serial} zaten bir emirde tahsis edilmiş" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" -msgstr "" +msgstr "Tahsis Miktarını Düzenle" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" -msgstr "" +msgstr "Tahsisi Sil" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" -msgstr "" +msgstr "Varsayılan Konum" #: part/bom.py:139 part/templates/part/part_base.html:124 msgid "Available Stock" @@ -3566,159 +3664,159 @@ msgstr "" #: part/bom.py:379 #, python-brace-format msgid "Unsupported file format: {f}" -msgstr "" +msgstr "Geçersiz dosya biçimi: {f}" #: part/bom.py:384 msgid "Error reading BOM file (invalid data)" -msgstr "" +msgstr "Malzeme listesi okurken hata (geçersiz data)" #: part/bom.py:386 msgid "Error reading BOM file (incorrect row size)" -msgstr "" +msgstr "Malzeme listesi okurken hata (geçersiz satır boyutu)" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" -msgstr "" +msgstr "Dosya Biçimi" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" -msgstr "" +msgstr "Çıktı dosyası biçimi seçin" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" -msgstr "" +msgstr "Dışa aktarılan malzeme listesine parça tedarikçisi verilerini dahil edin" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" -msgstr "" +msgstr "Malzeme Listesi Dosyası" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" -msgstr "" +msgstr "Yüklemek için Malzeme Listesi dosyası seçin" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" -msgstr "" +msgstr "Kategori parametre şablonlarını dahil et" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" -msgstr "" +msgstr "Üst kategorilerin parametre şablonlarını dahil et" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" -msgstr "" +msgstr "Parametre şablonunu aynı seviyedeki kategorilere ekle" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" -msgstr "" +msgstr "Parametre şablonunu tüm kategorilere ekle" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" #: part/models.py:73 msgid "Default location for parts in this category" -msgstr "" +msgstr "Bu kategori içindeki parçalar için varsayılan konum" #: part/models.py:76 msgid "Default keywords" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" -msgstr "" +msgstr "Parça Kategorileri" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" -msgstr "" +msgstr "Sonraki kullanılabilir seri numaraları" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" -msgstr "" +msgstr "Sonraki müsait seri numarası" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" -msgstr "" - -#: part/models.py:643 -msgid "Duplicate IPN not allowed in part settings" -msgstr "" +msgstr "En son seri numarası" #: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" +msgid "Duplicate IPN not allowed in part settings" +msgstr "Yinelenen DPN'ye parça ayarlarında izin verilmiyor" -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" -msgstr "" +msgstr "Şablon Mu" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" -msgstr "" +msgstr "Bu parça bir şablon parçası mı?" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" -msgstr "" +msgstr "Bu parça başka bir parçanın çeşidi mi?" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" -msgstr "" +msgstr "Çeşidi" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" -msgstr "" +msgstr "DPN" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" -msgstr "" +msgstr "Parça revizyon veya versiyon numarası" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" -msgstr "" +msgstr "Revizyon" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" -msgstr "" +msgstr "Varsayılan tedarikçi parçası" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" -msgstr "" +msgstr "Bu parça diğer parçalardan yapılabilir mi?" + +#: part/models.py:835 +msgid "Can this part be used to build other parts?" +msgstr "Bu parça diğer parçaların yapımında kullanılabilir mi?" #: part/models.py:841 -msgid "Can this part be used to build other parts?" -msgstr "" - -#: part/models.py:847 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" -msgstr "" +msgstr "Bu parça dış tedarikçilerden satın alınabilir mi?" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" -msgstr "" +msgstr "Bu parça müşterilere satılabilir mi?" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" -msgstr "" +msgstr "Test şablonları sadece takip edilebilir paçalar için oluşturulabilir" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" -msgstr "" +msgstr "Gerekli" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" -msgstr "" +msgstr "Testi geçmesi için bu gerekli mi?" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" -msgstr "" +msgstr "Parametre şablon adı benzersiz olmalıdır" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" -msgstr "" +msgstr "Parametre Şablonu" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" -msgstr "" +msgstr "Bu malzeme listesi, çeşit parçalar listesini kalıtsalıdır" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" -msgstr "" +msgstr "Çeşide İzin Ver" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" -msgstr "" +msgstr "Çeşit parçaların stok kalemleri bu malzeme listesinde kullanılabilir" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4227,11 +4312,11 @@ msgstr "" #: part/templates/part/bom_upload/upload_file.html:21 msgid "The BOM file must contain the required named columns as provided in the " -msgstr "" +msgstr "Malzeme Listesi dosyası gerekli sütün adlarını sağlandığı şekilde içermelidir " #: part/templates/part/bom_upload/upload_file.html:21 msgid "BOM Upload Template" -msgstr "" +msgstr "Malzeme Listesi Şablonu Yükle" #: part/templates/part/bom_upload/upload_file.html:22 msgid "Each part must already exist in the database" @@ -4254,88 +4339,97 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" -msgstr "" +msgstr "Kategori Detayları" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" -msgstr "" +msgstr "Alt kategoriler" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" -msgstr "" +msgstr "Parçalar (Alt kategoriler dahil)" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" -msgstr "" +msgstr "Kategori ayarla" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" -msgstr "" +msgstr "Kategori Ayarla" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" -msgstr "" +msgstr "Yeni konum oluştur" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" +msgstr "Yeni Stok konumu oluştur" + +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" msgstr "" #: part/templates/part/category_delete.html:5 @@ -4345,11 +4439,11 @@ msgstr "" #: part/templates/part/category_delete.html:8 #, python-format msgid "This category contains %(count)s child categories" -msgstr "" +msgstr "Bu kategori %(count)s alt kategori içermektedir" #: part/templates/part/category_delete.html:9 msgid "If this category is deleted, these child categories will be moved to the" -msgstr "" +msgstr "Bu kategori silinirse, alt kategoriler taşınacaktır" #: part/templates/part/category_delete.html:11 msgid "category" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,17 +4501,17 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" #: part/templates/part/detail.html:42 part/templates/part/part_base.html:188 msgid "Latest Serial Number" -msgstr "" +msgstr "Son Seri Numarası" #: part/templates/part/detail.html:47 msgid "No serial numbers recorded" -msgstr "" +msgstr "Seri numaraları kaydedildi" #: part/templates/part/detail.html:120 msgid "Stock Expiry Time" @@ -4438,11 +4531,11 @@ msgstr "" #: part/templates/part/detail.html:163 msgid "Part is a template part (variants can be made from this part)" -msgstr "" +msgstr "Bu parça bir şablon parçadır (Bu parçanın çeşitleri yapılabilir)" #: part/templates/part/detail.html:165 msgid "Part is not a template part" -msgstr "" +msgstr "Parça şablon parçası değil" #: part/templates/part/detail.html:173 msgid "Part can be assembled from other parts" @@ -4462,15 +4555,15 @@ msgstr "" #: part/templates/part/detail.html:193 msgid "Part stock is tracked by serial number" -msgstr "" +msgstr "Parça stoku seri numarası ile takip edilebilir" #: part/templates/part/detail.html:195 msgid "Part stock is not tracked by serial number" -msgstr "" +msgstr "Parça stoku seri numarası ile takip edilemez" #: part/templates/part/detail.html:203 part/templates/part/detail.html:205 msgid "Part can be purchased from external suppliers" -msgstr "" +msgstr "Bu parça harici tedarikçilerden satın alınabilir" #: part/templates/part/detail.html:213 msgid "Part can be sold to customers" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,170 +4599,73 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" -msgstr "" +msgstr "Parça Çeşitleri" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" -msgstr "" +msgstr "Çeşitler" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" -msgstr "" +msgstr "Tahsisler" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" -msgstr "" +msgstr "Parça Test Şablonları" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" #: part/templates/part/params.html:68 msgid "New Template" -msgstr "" +msgstr "Yeni Şablon" #: part/templates/part/params.html:69 msgid "Create New Parameter Template" -msgstr "" +msgstr "Yeni Parametre Şablonu Oluştur" #: part/templates/part/part_app_base.html:12 msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4672,7 +4677,7 @@ msgstr "" #: stock/templates/stock/item_base.html:75 #: stock/templates/stock/location.html:51 msgid "Barcode actions" -msgstr "" +msgstr "Barkod işlemleri" #: part/templates/part/part_base.html:42 #: stock/templates/stock/item_base.html:77 @@ -4684,7 +4689,7 @@ msgstr "" #: stock/templates/stock/item_base.html:93 #: stock/templates/stock/location.html:54 msgid "Print Label" -msgstr "" +msgstr "Etiket Yazdır" #: part/templates/part/part_base.html:48 msgid "Show pricing information" @@ -4696,7 +4701,7 @@ msgstr "" #: part/templates/part/part_base.html:67 msgid "Part actions" -msgstr "" +msgstr "Parça işlemleri" #: part/templates/part/part_base.html:70 msgid "Duplicate part" @@ -4717,39 +4722,111 @@ msgstr "" #: part/templates/part/part_base.html:113 #, python-format msgid "This part is a variant of %(link)s" -msgstr "" +msgstr "Bu parça %(link)s parçasının bir çeşididir" #: part/templates/part/part_base.html:130 templates/js/table_filters.js:161 msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" -msgstr "" +msgstr "Yapım İşi Emirleri için Gerekli" #: part/templates/part/part_base.html:150 msgid "Required for Sales Orders" -msgstr "" +msgstr "Satış Emirleri için Gerekli" #: part/templates/part/part_base.html:157 msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" +msgstr "Test Şablonu Ekle" + +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" msgstr "" #: part/templates/part/part_thumb.html:20 @@ -4779,19 +4856,105 @@ msgstr "" #: part/templates/part/partial_delete.html:44 #, python-format msgid "There are %(count)s suppliers defined for this part. If you delete this part, the following supplier parts will also be deleted:" -msgstr "" +msgstr "Bu parçası için tanımlanmış %(count)s tedarikçi bulunmaktadır. Bu parçayı silerseniz, aşağıdaki tedarikçi parçaları da silinecektir:" #: part/templates/part/partial_delete.html:55 #, python-format msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4804,29 +4967,29 @@ msgstr "" #: part/templates/part/set_category.html:9 msgid "Set category for the following parts" -msgstr "" +msgstr "Aşağıdaki parçalara kategori ayarla" #: part/templates/part/stock.html:10 msgid "Part Stock" -msgstr "" +msgstr "Parça Stoku" #: part/templates/part/stock.html:16 #, python-format msgid "Showing stock for all variants of %(full_name)s" -msgstr "" +msgstr "%(full_name)s için tüm çeşitlerin stokları gösteriliyor" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" -msgstr "" +msgstr "Stok Yok" #: part/templates/part/stock_count.html:9 templates/InvenTree/index.html:130 msgid "Low Stock" -msgstr "" +msgstr "Düşük Stok" #: part/templates/part/supplier.html:10 msgid "Part Suppliers" -msgstr "" +msgstr "Parça Tedarikçileri" #: part/templates/part/track.html:10 msgid "Part Tracking" @@ -4838,317 +5001,297 @@ msgstr "" #: part/templates/part/variant_part.html:9 msgid "Create new part variant" -msgstr "" +msgstr "Yeni parça çeşidi oluştur" #: part/templates/part/variant_part.html:10 #, python-format msgid "Create a new variant of template '%(full_name)s'." -msgstr "" +msgstr "%(full_name)s şablonu için yeni bir çeşit oluştur." #: part/templates/part/variants.html:19 msgid "Create new variant" -msgstr "" +msgstr "Yeni çeşit oluştur" #: part/templates/part/variants.html:20 msgid "New Variant" -msgstr "" +msgstr "Yeni Çeşit" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" -msgstr "" +msgstr "Çeşit Oluştur" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Oluştur" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Düzenle" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" -msgstr "" +msgstr "Parça Parametre Şablonu Sil" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Oluştur" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Düzenle" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" -msgstr "" +msgstr "Kategori Parametre Şablonu Sil" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" -msgstr "" +msgstr "Şablon adı" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" -msgstr "" +msgstr "Rapor şablon dosyası" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" -msgstr "" +msgstr "Rapor şablon tanımı" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" +msgstr "Revizyon numarası raporla (otomatik artış)" + +#: report/models.py:291 +msgid "Pattern for generating report filenames" msgstr "" -#: report/models.py:275 +#: report/models.py:298 msgid "Report template is enabled" -msgstr "" +msgstr "Rapor şablonu etkin" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" -msgstr "" +msgstr "Stok kalemi sorgu filtreleri (anahter=değer [key=value] olarak virgülle ayrılmış liste)" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" #: report/templates/report/inventree_build_order_base.html:147 msgid "Required For" -msgstr "" +msgstr "İçin Gerekli Olan" #: report/templates/report/inventree_po_report.html:85 #: report/templates/report/inventree_so_report.html:85 @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" -msgstr "" +msgstr "{n} öge için stok güncellendi" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" -msgstr "" +msgstr "Bu stok kalemi için son kullanma tarihi" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" -msgstr "" +msgstr "Benzersiz seri numaraları giriniz (veya boş bırakınız)" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" -msgstr "" +msgstr "Seri numaralandırılmış stok için hedef konum(varsayılan olarak, geçerli konumda kalacaktır)" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" -msgstr "" +msgstr "Seri numaraları" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" -msgstr "" +msgstr "Benzersiz seri numaraları (miktar ile eşleşmeli)" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" -msgstr "" +msgstr "İşlem notu ekle (isteğe bağlı)" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" -msgstr "" +msgstr "Test raporu şablonu seç" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" -msgstr "" +msgstr "Alt konumları dahil et" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" -msgstr "" +msgstr "Stok kalemlerine alt konumları dahil et" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" -msgstr "" +msgstr "Kurulacak stok kalemi" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" -msgstr "" +msgstr "Atanacak stok miktarı" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" -msgstr "" +msgstr "Sökülen ögeler için hedef konum" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" -msgstr "" +msgstr "Kurulu stok kalemlerinin kaldırılmasını onayla" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" -msgstr "" +msgstr "Hedef stok konumu" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" -msgstr "" +msgstr "Not ekle (gerekli)" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" -msgstr "" +msgstr "Stok ayarlamasını onayla" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" -msgstr "" +msgstr "Stok kalemlerinin hareketini onaylayın" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" -msgstr "" +msgstr "Varsayılan Konum Ayarla" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" -msgstr "" +msgstr "Hedefi seçili parçalar için varsayılan konum olarak ayarla" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" -msgstr "" +msgstr "Bu seri numarasına sahip stok kalemi zaten var" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" -msgstr "" +msgstr "Seri numarası olan ögenin miktarı bir olmalı" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" -msgstr "" +msgstr "Miktar birden büyük ise seri numarası ayarlanamaz" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" -msgstr "" +msgstr "Üst Stok Kalemi" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" -msgstr "" +msgstr "Bu stok kalemi için tedarikçi parçası seçin" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" -msgstr "" +msgstr "Stok Konumu" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" -msgstr "" +msgstr "Bu öge için seri numarası" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 -msgid "Serial numbers must be a list of integers" -msgstr "" - #: stock/models.py:1029 -msgid "Quantity does not match serial numbers" -msgstr "" +msgid "Serial numbers must be a list of integers" +msgstr "Seri numaraları tam sayı listesi olmalı" -#: stock/models.py:1036 +#: stock/models.py:1032 +msgid "Quantity does not match serial numbers" +msgstr "Miktar seri numaları ile eşleşmiyor" + +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" -msgstr "" +msgstr "Seri numaraları zaten mevcut: {exists}" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" -msgstr "" +msgstr "Stok kalemi stokta olmadığı için taşınamaz" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5503,11 +5646,11 @@ msgstr "" #: stock/templates/stock/item_base.html:84 templates/stock_table.html:31 msgid "Scan to Location" -msgstr "" +msgstr "Konuma Tara" #: stock/templates/stock/item_base.html:91 msgid "Printing actions" -msgstr "" +msgstr "Yazdırma işlemleri" #: stock/templates/stock/item_base.html:95 #: stock/templates/stock/item_tests.html:27 @@ -5516,7 +5659,7 @@ msgstr "" #: stock/templates/stock/item_base.html:104 msgid "Stock adjustment actions" -msgstr "" +msgstr "Stok ayarlama işlemleri" #: stock/templates/stock/item_base.html:108 #: stock/templates/stock/location.html:65 templates/stock_table.html:57 @@ -5533,7 +5676,7 @@ msgstr "" #: stock/templates/stock/item_base.html:117 msgid "Serialize stock" -msgstr "" +msgstr "Stoku seri numarala" #: stock/templates/stock/item_base.html:121 msgid "Transfer stock" @@ -5558,11 +5701,11 @@ msgstr "" #: stock/templates/stock/item_base.html:140 #: stock/templates/stock/location.html:62 msgid "Stock actions" -msgstr "" +msgstr "Stok işlemleri" #: stock/templates/stock/item_base.html:143 msgid "Convert to variant" -msgstr "" +msgstr "Çeşide çevir" #: stock/templates/stock/item_base.html:146 msgid "Duplicate stock item" @@ -5590,7 +5733,7 @@ msgstr "" #: stock/templates/stock/item_base.html:192 msgid "This stock item has not passed all required tests" -msgstr "" +msgstr "Stok kalemi tüm gerekli testleri geçmedi" #: stock/templates/stock/item_base.html:200 #, python-format @@ -5604,7 +5747,7 @@ msgstr "" #: stock/templates/stock/item_base.html:214 msgid "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." -msgstr "" +msgstr "Bu stok kalemi seri numaları - Benzersiz bir seri numarasına sahip ve miktarı ayarlanamaz." #: stock/templates/stock/item_base.html:218 msgid "This stock item cannot be deleted as it has child items" @@ -5618,9 +5761,9 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" -msgstr "" +msgstr "Konum ayarlanmadı" #: stock/templates/stock/item_base.html:296 msgid "Barcode Identifier" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" -msgstr "" +msgstr "Bu stok kaleminin süresi %(item.expiry_date)s tarihinde sona erdi" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" -msgstr "" +msgstr "Bu stok kaleminin süresi %(item.expiry_date)s tarihinde sona erecek" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5671,7 +5822,7 @@ msgstr "" #: stock/templates/stock/item_install.html:7 msgid "Install another StockItem into this item." -msgstr "" +msgstr "Bu ögeye başka bir stok kalemi ekle." #: stock/templates/stock/item_install.html:10 msgid "Stock items can only be installed if they meet the following criteria" @@ -5679,11 +5830,11 @@ msgstr "" #: stock/templates/stock/item_install.html:13 msgid "The StockItem links to a Part which is in the BOM for this StockItem" -msgstr "" +msgstr "Bu stok kalemi, kendi malzeme listesinin bir parçasına bağlıdır" #: stock/templates/stock/item_install.html:14 msgid "The StockItem is currently in stock" -msgstr "" +msgstr "Bu stok kalemi şu anda stokta" #: stock/templates/stock/item_installed.html:11 #: stock/templates/stock/navbar.html:27 @@ -5692,11 +5843,11 @@ msgstr "" #: stock/templates/stock/item_serialize.html:5 msgid "Create serialized items from this stock item." -msgstr "" +msgstr "Bu stok kalemi için seri numaralandırılmış ögeler oluştur." #: stock/templates/stock/item_serialize.html:7 msgid "Select quantity to serialize, and unique serial numbers." -msgstr "" +msgstr "Seri numaralandırılacak miktarı ve benzersiz seri numaralarını seçin." #: stock/templates/stock/item_tests.html:11 #: stock/templates/stock/navbar.html:19 stock/templates/stock/navbar.html:22 @@ -5711,9 +5862,22 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." -msgstr "" +msgstr "Bu konumun sahipleri listesinde değilsiniz. Bu stok konumu düzenlenemez." #: stock/templates/stock/location.html:37 msgid "All stock items" @@ -5725,47 +5889,47 @@ msgstr "" #: stock/templates/stock/location.html:71 msgid "Location actions" -msgstr "" +msgstr "Konum işlemleri" #: stock/templates/stock/location.html:73 msgid "Edit location" -msgstr "" +msgstr "Konumu düzenle" #: stock/templates/stock/location.html:75 msgid "Delete location" -msgstr "" +msgstr "Konumu sil" #: stock/templates/stock/location.html:87 msgid "Location Details" -msgstr "" +msgstr "Konum Detayları" #: stock/templates/stock/location.html:92 msgid "Location Path" -msgstr "" +msgstr "Konum Yolu" #: stock/templates/stock/location.html:97 msgid "Location Description" -msgstr "" +msgstr "Konum Tanımı" #: stock/templates/stock/location.html:102 #: stock/templates/stock/location_navbar.html:11 #: stock/templates/stock/location_navbar.html:18 #: stock/templates/stock/sublocation.html:16 msgid "Sublocations" -msgstr "" +msgstr "Alt konumlar" #: stock/templates/stock/location.html:112 msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" -msgstr "" +msgstr "Stok Konumları" #: stock/templates/stock/location_delete.html:7 msgid "Are you sure you want to delete this stock location?" -msgstr "" +msgstr "Bu stok konumunu silmek istediğinizden emin misiniz?" #: stock/templates/stock/navbar.html:11 msgid "Stock Item Tracking" @@ -5799,30 +5963,30 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" -msgstr "" +msgstr "Stok Kalemine Dönüştür" #: stock/templates/stock/stockitem_convert.html:8 #, python-format msgid "This stock item is current an instance of %(part)s" -msgstr "" +msgstr "Bu stok kalemi şu anda %(part)s parçasının örneğidir" #: stock/templates/stock/stockitem_convert.html:9 msgid "It can be converted to one of the part variants listed below." -msgstr "" +msgstr "Aşağıda listelenen parça çeşitlerinden birine dönüştürülebilir." #: stock/templates/stock/stockitem_convert.html:14 msgid "This action cannot be easily undone" -msgstr "" +msgstr "Bu işlem kolayca geri alınamaz" #: stock/templates/stock/sublocation.html:23 templates/stock_table.html:37 msgid "Printing Actions" -msgstr "" +msgstr "Yazdırma İşlemleri" #: stock/templates/stock/sublocation.html:27 templates/stock_table.html:41 msgid "Print labels" -msgstr "" +msgstr "Etiketleri yazdır" #: stock/templates/stock/tracking_delete.html:6 msgid "Are you sure you want to delete this stock tracking entry?" @@ -5830,216 +5994,188 @@ msgstr "" #: stock/views.py:123 msgid "Edit Stock Location" -msgstr "" +msgstr "Stok konumunu düzenle" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" -msgstr "" +msgstr "Sahip gerekli (sahip kontrolü etkinleştirildi)" #: stock/views.py:245 msgid "Stock Location QR code" -msgstr "" +msgstr "Stok Konumu QR Kodu" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" -msgstr "" +msgstr "Geçerli bir konum belirtiniz" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" -msgstr "" +msgstr "Herhangi bir işlem gerçekleştirilmedi" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" -msgstr "" +msgstr "Stoku Seri Numarala" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" -msgstr "" +msgstr "Stok Konumunu Sil" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,13 +6259,13 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" -msgstr "" +msgstr "Stok konumu ayarlanmadı" #: templates/InvenTree/settings/appearance.html:10 msgid "Theme Settings" @@ -6157,47 +6297,47 @@ msgstr "" #: templates/InvenTree/settings/category.html:9 msgid "Category Settings" -msgstr "" +msgstr "Kategori Ayarları" #: templates/InvenTree/settings/category.html:25 msgid "Category Parameter Templates" -msgstr "" +msgstr "Kategori Parametre Şablonu" #: templates/InvenTree/settings/category.html:52 msgid "No category parameter templates found" -msgstr "" +msgstr "Kategori parametre şablonu bulunamadı" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" -msgstr "" +msgstr "Şablonu Düzenle" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" -msgstr "" +msgstr "Şablonu Sil" #: templates/InvenTree/settings/currencies.html:10 msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,13 +6361,21 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "Parça Parametre Şablonu" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" -msgstr "" +msgstr "Parça parametre şablonu bulunamadı" #: templates/InvenTree/settings/po.html:9 msgid "Purchase Order Settings" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6472,7 +6628,7 @@ msgstr "" #: templates/js/barcode.js:418 msgid "Check Stock Items into Location" -msgstr "" +msgstr "Stok Kalemlerini bu konuma kaydet" #: templates/js/barcode.js:422 templates/js/barcode.js:547 msgid "Check In" @@ -6488,7 +6644,7 @@ msgstr "" #: templates/js/barcode.js:485 msgid "Stock Item already in this location" -msgstr "" +msgstr "Stok kalemi zaten bu konumda" #: templates/js/barcode.js:492 msgid "Added stock item" @@ -6500,13 +6656,13 @@ msgstr "" #: templates/js/barcode.js:542 msgid "Check Into Location" -msgstr "" +msgstr "Konuma Kaydet" #: templates/js/barcode.js:605 msgid "Barcode does not match a valid location" -msgstr "" +msgstr "Barkod geçerli bir konumla eşleşmiyor" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,77 +6722,121 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" -msgstr "" +msgstr "Gerekli Parça" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" -msgstr "" +msgstr "Şablon Parça" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" #: templates/js/filters.js:167 templates/js/filters.js:397 msgid "true" -msgstr "" +msgstr "doğru" #: templates/js/filters.js:171 templates/js/filters.js:398 msgid "false" -msgstr "" +msgstr "yanlış" #: templates/js/filters.js:193 msgid "Select filter" @@ -6650,33 +6854,110 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "Bu fonksiyona erişmek için gerekli izinlere sahip değilsiniz" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" #: templates/js/label.js:11 msgid "Stock item(s) must be selected before printing labels" -msgstr "" +msgstr "Etiket yazdırılmadan önce stok kalemleri seçilmeli" #: templates/js/label.js:29 templates/js/label.js:79 msgid "No Labels Found" -msgstr "" +msgstr "Etiket Bulunamadı" #: templates/js/label.js:30 msgid "No labels found which match selected stock item(s)" -msgstr "" +msgstr "Seçili stok kalemleri için etiket bulunamadı" #: templates/js/label.js:61 msgid "Select Stock Locations" -msgstr "" +msgstr "Stok Konumu Seç" #: templates/js/label.js:62 msgid "Stock location(s) must be selected before printing labels" -msgstr "" +msgstr "Etiket yazdırılmadan önce stok konumları seçilmeli" #: templates/js/label.js:80 msgid "No labels found which match selected stock location(s)" -msgstr "" +msgstr "Seçili konumlarla eşleşen etiket bulunamadı" #: templates/js/label.js:154 msgid "stock items selected" @@ -6684,117 +6965,111 @@ msgstr "" #: templates/js/label.js:162 msgid "Select Label" -msgstr "" +msgstr "Etiket Seç" #: templates/js/label.js:177 msgid "Select Label Template" -msgstr "" +msgstr "Etiket Şablonu Seç" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6821,41 +7096,56 @@ msgstr "" #: templates/js/part.js:194 msgid "No variants found" -msgstr "" +msgstr "Çeşit bulunamadı" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" -msgstr "" +msgstr "Sorgu ile eşleşen test şablonu bulunamadı" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6865,11 +7155,11 @@ msgstr "" #: templates/js/report.js:55 msgid "Select Report Template" -msgstr "" +msgstr "Rapor Şablonu Seç" #: templates/js/report.js:70 msgid "Select Test Report Template" -msgstr "" +msgstr "Test Raporu Şablonu Seç" #: templates/js/report.js:99 msgid "Stock item(s) must be selected before printing reports" @@ -6883,7 +7173,7 @@ msgstr "" #: templates/js/report.js:117 msgid "No report templates found which match selected stock item(s)" -msgstr "" +msgstr "Seçili stok kalemleri için rapor şablonu bulunamadı" #: templates/js/report.js:152 msgid "Select Builds" @@ -6895,7 +7185,7 @@ msgstr "" #: templates/js/report.js:170 msgid "No report templates found which match selected build(s)" -msgstr "" +msgstr "Seçili yapım işleri için rapor şablonu bulunamadı" #: templates/js/report.js:205 msgid "Select Parts" @@ -6907,7 +7197,7 @@ msgstr "" #: templates/js/report.js:224 msgid "No report templates found which match selected part(s)" -msgstr "" +msgstr "Seçili parçalar için rapor şablonu bulunamadı" #: templates/js/report.js:259 msgid "Select Purchase Orders" @@ -6919,7 +7209,7 @@ msgstr "" #: templates/js/report.js:278 templates/js/report.js:332 msgid "No report templates found which match selected orders" -msgstr "" +msgstr "Seçili emirler için rapor şablonu bulunamadı" #: templates/js/report.js:313 msgid "Select Sales Orders" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" -msgstr "" +msgstr "konumlar" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" -msgstr "" +msgstr "Tanımsız konum" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" -msgstr "" +msgstr "Konum artık yok" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" -msgstr "" +msgstr "Yeni Konum Oluştur" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" -msgstr "" +msgstr "Seri No" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7115,47 +7405,47 @@ msgstr "" #: templates/js/table_filters.js:55 msgid "Allow Variant Stock" -msgstr "" +msgstr "Çeşit Stokuna İzin Ver" #: templates/js/table_filters.js:76 msgid "Include locations" -msgstr "" +msgstr "Konumları dahil et" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" #: templates/js/table_filters.js:97 templates/js/table_filters.js:186 msgid "Is Serialized" -msgstr "" +msgstr "Seri Numaralı" #: templates/js/table_filters.js:100 templates/js/table_filters.js:193 msgid "Serial number GTE" -msgstr "" +msgstr "Seri numarası BvE" #: templates/js/table_filters.js:101 templates/js/table_filters.js:194 msgid "Serial number greater than or equal to" -msgstr "" +msgstr "Seri numarası büyük veya eşit" #: templates/js/table_filters.js:104 templates/js/table_filters.js:197 msgid "Serial number LTE" -msgstr "" +msgstr "Seri numarası KvE" #: templates/js/table_filters.js:105 templates/js/table_filters.js:198 msgid "Serial number less than or equal to" -msgstr "" +msgstr "Seri numarası küçük veya eşit" #: templates/js/table_filters.js:108 templates/js/table_filters.js:109 #: templates/js/table_filters.js:189 templates/js/table_filters.js:190 msgid "Serial number" -msgstr "" +msgstr "Seri numarası" #: templates/js/table_filters.js:113 templates/js/table_filters.js:207 msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7177,7 +7467,7 @@ msgstr "" #: templates/js/table_filters.js:139 msgid "Include stock in sublocations" -msgstr "" +msgstr "Alt konumlardaki stoku dahil et" #: templates/js/table_filters.js:144 msgid "Show stock items which are depleted" @@ -7205,11 +7495,11 @@ msgstr "" #: templates/js/table_filters.js:171 msgid "Include Variants" -msgstr "" +msgstr "Çeşitleri Dahil Et" #: templates/js/table_filters.js:172 msgid "Include stock items for variant parts" -msgstr "" +msgstr "Çeşit parçaların stok kalemlerini dahil et" #: templates/js/table_filters.js:176 msgid "Installed" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 -msgid "Include parts in subcategories" -msgstr "" - -#: templates/js/table_filters.js:305 -msgid "Has IPN" -msgstr "" - #: templates/js/table_filters.js:306 +msgid "Include parts in subcategories" +msgstr "Alt kategorilerdeki parçaları dahil et" + +#: templates/js/table_filters.js:310 +msgid "Has IPN" +msgstr "DPN Var" + +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7482,7 +7776,7 @@ msgstr "" #: templates/stock_table.html:27 msgid "Barcode Actions" -msgstr "" +msgstr "Barkod İşlemleri" #: templates/stock_table.html:43 msgid "Print test reports" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/locale/zh/LC_MESSAGES/django.po b/InvenTree/locale/zh/LC_MESSAGES/django.po index 9892439445..a5b51e77ec 100644 --- a/InvenTree/locale/zh/LC_MESSAGES/django.po +++ b/InvenTree/locale/zh/LC_MESSAGES/django.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: inventree\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-16 22:40+0000\n" -"PO-Revision-Date: 2021-06-16 22:41\n" +"POT-Creation-Date: 2021-07-03 12:15+0000\n" +"PO-Revision-Date: 2021-07-03 12:44\n" "Last-Translator: \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" @@ -29,14 +29,14 @@ msgstr "未指定操作" msgid "No matching action found" msgstr "未找到指定操作" -#: InvenTree/fields.py:44 +#: InvenTree/fields.py:99 msgid "Enter date" msgstr "输入日期" #: InvenTree/forms.py:112 build/forms.py:102 build/forms.py:123 #: build/forms.py:145 build/forms.py:169 build/forms.py:185 build/forms.py:227 -#: order/forms.py:27 order/forms.py:38 order/forms.py:49 order/forms.py:60 -#: order/forms.py:71 part/forms.py:134 +#: order/forms.py:30 order/forms.py:41 order/forms.py:52 order/forms.py:63 +#: order/forms.py:74 part/forms.py:118 templates/js/forms.js:486 msgid "Confirm" msgstr "确认" @@ -72,134 +72,143 @@ msgstr "应用主题" msgid "Select Category" msgstr "选择分类" -#: InvenTree/helpers.py:377 +#: InvenTree/helpers.py:396 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:384 order/models.py:247 order/models.py:357 -#: stock/views.py:1795 +#: InvenTree/helpers.py:403 order/models.py:311 order/models.py:421 +#: stock/views.py:1627 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:387 +#: InvenTree/helpers.py:406 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:409 InvenTree/helpers.py:412 InvenTree/helpers.py:415 -#: InvenTree/helpers.py:440 +#: InvenTree/helpers.py:428 InvenTree/helpers.py:431 InvenTree/helpers.py:434 +#: InvenTree/helpers.py:459 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:445 +#: InvenTree/helpers.py:464 #, python-brace-format msgid "Duplicate serial: {g}" msgstr "" -#: InvenTree/helpers.py:453 +#: InvenTree/helpers.py:472 msgid "No serial numbers found" msgstr "未找到序列号" -#: InvenTree/helpers.py:457 +#: InvenTree/helpers.py:476 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/models.py:59 stock/models.py:1763 +#: InvenTree/models.py:61 stock/models.py:1778 msgid "Attachment" msgstr "附件" -#: InvenTree/models.py:60 +#: InvenTree/models.py:62 msgid "Select file to attach" msgstr "选择附件" -#: InvenTree/models.py:62 templates/attachment_table.html:16 +#: InvenTree/models.py:64 templates/js/attachment.js:52 msgid "Comment" msgstr "注释" -#: InvenTree/models.py:62 +#: InvenTree/models.py:64 msgid "File comment" msgstr "文件注释" -#: InvenTree/models.py:68 InvenTree/models.py:69 part/models.py:1999 +#: InvenTree/models.py:70 InvenTree/models.py:71 part/models.py:2043 #: report/templates/report/inventree_test_report_base.html:91 -#: templates/js/stock.js:1154 +#: templates/js/stock.js:1193 msgid "User" msgstr "用户" -#: InvenTree/models.py:72 +#: InvenTree/models.py:74 msgid "upload date" msgstr "上传日期" -#: InvenTree/models.py:107 InvenTree/models.py:108 label/models.py:102 -#: part/models.py:686 part/models.py:2140 part/templates/part/params.html:27 -#: report/models.py:179 templates/InvenTree/search.html:137 -#: templates/InvenTree/search.html:289 templates/js/part.js:118 -#: templates/js/part.js:641 templates/js/stock.js:947 +#: InvenTree/models.py:102 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:118 InvenTree/models.py:119 company/models.py:414 +#: label/models.py:103 part/models.py:680 part/models.py:2192 +#: part/templates/part/params.html:27 report/models.py:180 +#: templates/InvenTree/search.html:137 templates/InvenTree/search.html:289 +#: templates/js/company.js:359 templates/js/part.js:118 +#: templates/js/part.js:642 templates/js/stock.js:986 msgid "Name" msgstr "名称" -#: InvenTree/models.py:114 build/models.py:135 -#: build/templates/build/detail.html:21 company/models.py:339 -#: company/models.py:491 company/templates/company/detail.html:27 +#: InvenTree/models.py:125 build/models.py:139 +#: build/templates/build/detail.html:21 company/models.py:353 +#: company/models.py:554 company/templates/company/detail.html:27 #: company/templates/company/manufacturer_part_base.html:72 #: company/templates/company/supplier_part_base.html:71 -#: company/templates/company/supplier_part_detail.html:31 label/models.py:109 -#: order/models.py:103 order/templates/order/purchase_order_detail.html:147 -#: part/models.py:710 part/templates/part/detail.html:54 -#: part/templates/part/set_category.html:14 report/models.py:192 -#: report/models.py:505 report/models.py:544 +#: company/templates/company/supplier_part_detail.html:31 label/models.py:110 +#: order/models.py:154 order/templates/order/purchase_order_detail.html:174 +#: part/models.py:704 part/templates/part/detail.html:54 +#: part/templates/part/set_category.html:14 report/models.py:193 +#: report/models.py:530 report/models.py:569 #: report/templates/report/inventree_build_order_base.html:118 #: templates/InvenTree/search.html:144 templates/InvenTree/search.html:224 #: templates/InvenTree/search.html:296 #: templates/InvenTree/settings/header.html:9 templates/js/bom.js:190 -#: templates/js/build.js:746 templates/js/build.js:1014 -#: templates/js/company.js:56 templates/js/order.js:183 -#: templates/js/order.js:280 templates/js/part.js:177 templates/js/part.js:260 -#: templates/js/part.js:437 templates/js/part.js:653 templates/js/part.js:721 -#: templates/js/stock.js:552 templates/js/stock.js:959 -#: templates/js/stock.js:1004 +#: templates/js/build.js:834 templates/js/build.js:1102 +#: templates/js/company.js:125 templates/js/order.js:245 +#: templates/js/order.js:347 templates/js/part.js:177 templates/js/part.js:260 +#: templates/js/part.js:437 templates/js/part.js:654 templates/js/part.js:722 +#: templates/js/stock.js:557 templates/js/stock.js:998 +#: templates/js/stock.js:1043 msgid "Description" msgstr "" -#: InvenTree/models.py:115 +#: InvenTree/models.py:126 msgid "Description (optional)" msgstr "" -#: InvenTree/models.py:123 +#: InvenTree/models.py:134 msgid "parent" msgstr "" -#: InvenTree/settings.py:503 -msgid "English" -msgstr "" - -#: InvenTree/settings.py:504 -msgid "French" +#: InvenTree/serializers.py:52 +msgid "Must be a valid number" msgstr "" #: InvenTree/settings.py:505 -msgid "German" +msgid "English" msgstr "" #: InvenTree/settings.py:506 -msgid "Polish" +msgid "French" msgstr "" #: InvenTree/settings.py:507 +msgid "German" +msgstr "" + +#: InvenTree/settings.py:508 +msgid "Polish" +msgstr "" + +#: InvenTree/settings.py:509 msgid "Turkish" msgstr "" -#: InvenTree/status.py:93 +#: InvenTree/status.py:94 msgid "Background worker check failed" msgstr "" -#: InvenTree/status.py:97 +#: InvenTree/status.py:98 msgid "Email backend not configured" msgstr "" -#: InvenTree/status.py:100 +#: InvenTree/status.py:101 msgid "InvenTree system health checks failed" msgstr "" @@ -372,27 +381,27 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: InvenTree/views.py:605 +#: InvenTree/views.py:608 msgid "Delete Item" msgstr "" -#: InvenTree/views.py:654 +#: InvenTree/views.py:657 msgid "Check box to confirm item deletion" msgstr "" -#: InvenTree/views.py:669 templates/InvenTree/settings/user.html:18 +#: InvenTree/views.py:672 templates/InvenTree/settings/user.html:18 msgid "Edit User Information" msgstr "" -#: InvenTree/views.py:680 templates/InvenTree/settings/user.html:22 +#: InvenTree/views.py:683 templates/InvenTree/settings/user.html:22 msgid "Set Password" msgstr "" -#: InvenTree/views.py:699 +#: InvenTree/views.py:702 msgid "Password fields must match" msgstr "" -#: InvenTree/views.py:950 templates/navbar.html:95 +#: InvenTree/views.py:953 templates/navbar.html:95 msgid "System Information" msgstr "" @@ -445,50 +454,48 @@ msgid "Order target date" msgstr "" #: build/forms.py:42 build/templates/build/build_base.html:146 -#: build/templates/build/detail.html:121 order/forms.py:109 order/forms.py:144 +#: build/templates/build/detail.html:121 #: order/templates/order/order_base.html:124 #: order/templates/order/sales_order_base.html:119 #: report/templates/report/inventree_build_order_base.html:126 -#: templates/js/build.js:793 templates/js/order.js:200 -#: templates/js/order.js:298 +#: templates/js/build.js:881 templates/js/order.js:262 +#: templates/js/order.js:365 msgid "Target Date" msgstr "" -#: build/forms.py:43 build/models.py:225 +#: build/forms.py:43 build/models.py:229 msgid "Target date for build completion. Build will be overdue after this date." msgstr "" -#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1346 +#: build/forms.py:48 build/forms.py:90 build/forms.py:266 build/models.py:1354 #: build/templates/build/allocation_card.html:23 #: build/templates/build/auto_allocate.html:17 #: build/templates/build/build_base.html:133 -#: build/templates/build/detail.html:31 common/models.py:699 -#: company/forms.py:176 company/templates/company/supplier_part_pricing.html:77 -#: order/forms.py:188 order/forms.py:205 order/forms.py:240 order/forms.py:262 -#: order/forms.py:279 order/models.py:616 order/models.py:817 -#: order/templates/order/order_wizard/match_parts.html:29 -#: order/templates/order/order_wizard/select_parts.html:32 -#: order/templates/order/purchase_order_detail.html:179 -#: order/templates/order/sales_order_detail.html:70 -#: order/templates/order/sales_order_detail.html:77 -#: order/templates/order/sales_order_detail.html:162 -#: order/templates/order/sales_order_detail.html:230 part/forms.py:342 -#: part/forms.py:372 part/forms.py:388 part/models.py:2270 -#: part/templates/part/allocation.html:19 -#: part/templates/part/allocation.html:53 -#: part/templates/part/order_prices.html:175 -#: part/templates/part/part_pricing.html:13 -#: part/templates/part/sale_prices.html:85 +#: build/templates/build/detail.html:31 common/models.py:741 +#: company/forms.py:124 company/templates/company/supplier_part_pricing.html:79 +#: order/forms.py:120 order/forms.py:142 order/forms.py:159 order/models.py:702 +#: order/models.py:941 order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 +#: order/templates/order/purchase_order_detail.html:206 +#: order/templates/order/sales_order_detail.html:80 +#: order/templates/order/sales_order_detail.html:87 +#: order/templates/order/sales_order_detail.html:172 +#: order/templates/order/sales_order_detail.html:244 part/forms.py:314 +#: part/forms.py:344 part/forms.py:360 part/forms.py:376 part/models.py:2330 +#: part/templates/part/part_pricing.html:16 part/templates/part/prices.html:377 +#: part/templates/part/prices.html:474 #: report/templates/report/inventree_build_order_base.html:114 #: report/templates/report/inventree_po_report.html:91 #: report/templates/report/inventree_so_report.html:91 #: report/templates/report/inventree_test_report_base.html:77 -#: stock/forms.py:175 stock/forms.py:308 +#: stock/forms.py:142 stock/forms.py:275 #: stock/templates/stock/item_base.html:255 #: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364 -#: templates/js/bom.js:205 templates/js/build.js:486 templates/js/build.js:1024 -#: templates/js/part.js:795 templates/js/stock.js:1139 -#: templates/js/stock.js:1358 +#: templates/js/bom.js:205 templates/js/build.js:233 templates/js/build.js:572 +#: templates/js/build.js:1112 templates/js/model_renderers.js:43 +#: templates/js/order.js:460 templates/js/part.js:827 templates/js/part.js:949 +#: templates/js/part.js:1005 templates/js/stock.js:1178 +#: templates/js/stock.js:1397 msgid "Quantity" msgstr "" @@ -500,7 +507,7 @@ msgstr "" msgid "Enter quantity for build output" msgstr "" -#: build/forms.py:95 order/forms.py:234 stock/forms.py:118 +#: build/forms.py:95 order/forms.py:114 stock/forms.py:85 msgid "Serial Numbers" msgstr "" @@ -529,12 +536,12 @@ msgid "Mark build as complete" msgstr "" #: build/forms.py:210 build/templates/build/auto_allocate.html:18 -#: order/forms.py:82 stock/forms.py:347 -#: stock/templates/stock/item_base.html:285 +#: stock/forms.py:314 stock/templates/stock/item_base.html:285 #: stock/templates/stock/stock_adjust.html:17 #: templates/InvenTree/search.html:260 templates/js/barcode.js:363 -#: templates/js/barcode.js:531 templates/js/build.js:500 -#: templates/js/stock.js:639 templates/js/stock.js:1031 +#: templates/js/barcode.js:531 templates/js/build.js:218 +#: templates/js/build.js:586 templates/js/order.js:445 +#: templates/js/stock.js:643 templates/js/stock.js:1070 msgid "Location" msgstr "" @@ -543,13 +550,13 @@ msgid "Location of completed parts" msgstr "" #: build/forms.py:215 build/templates/build/build_base.html:138 -#: build/templates/build/detail.html:59 order/models.py:468 +#: build/templates/build/detail.html:59 order/models.py:545 #: order/templates/order/receive_parts.html:24 -#: stock/templates/stock/item_base.html:403 templates/InvenTree/search.html:252 -#: templates/js/barcode.js:119 templates/js/build.js:780 -#: templates/js/order.js:187 templates/js/order.js:285 -#: templates/js/stock.js:626 templates/js/stock.js:1108 -#: templates/js/stock.js:1374 +#: stock/templates/stock/item_base.html:408 templates/InvenTree/search.html:252 +#: templates/js/barcode.js:119 templates/js/build.js:868 +#: templates/js/order.js:249 templates/js/order.js:352 +#: templates/js/stock.js:630 templates/js/stock.js:1147 +#: templates/js/stock.js:1413 msgid "Status" msgstr "" @@ -581,286 +588,284 @@ msgstr "" msgid "Select quantity of stock to allocate" msgstr "" -#: build/models.py:66 build/templates/build/build_base.html:9 +#: build/models.py:70 build/templates/build/build_base.html:9 #: build/templates/build/build_base.html:73 -#: part/templates/part/allocation.html:23 #: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/build.js:195 msgid "Build Order" msgstr "" -#: build/models.py:67 build/templates/build/index.html:8 +#: build/models.py:71 build/templates/build/index.html:8 #: build/templates/build/index.html:15 order/templates/order/so_builds.html:12 #: order/templates/order/so_navbar.html:19 -#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:55 -#: part/templates/part/navbar.html:58 templates/InvenTree/index.html:183 +#: order/templates/order/so_navbar.html:22 part/templates/part/navbar.html:58 +#: part/templates/part/navbar.html:61 templates/InvenTree/index.html:191 #: templates/InvenTree/search.html:185 -#: templates/InvenTree/settings/tabs.html:34 users/models.py:43 +#: templates/InvenTree/settings/tabs.html:34 users/models.py:44 msgid "Build Orders" msgstr "" -#: build/models.py:127 +#: build/models.py:131 msgid "Build Order Reference" msgstr "" -#: build/models.py:128 order/models.py:101 order/models.py:618 -#: order/templates/order/purchase_order_detail.html:174 -#: order/templates/order/sales_order_detail.html:225 part/models.py:2279 +#: build/models.py:132 order/models.py:242 order/models.py:529 +#: order/models.py:709 order/templates/order/purchase_order_detail.html:201 +#: order/templates/order/sales_order_detail.html:239 part/models.py:2339 #: report/templates/report/inventree_po_report.html:92 #: report/templates/report/inventree_so_report.html:92 templates/js/bom.js:197 -#: templates/js/build.js:575 templates/js/build.js:1018 +#: templates/js/build.js:661 templates/js/build.js:1106 msgid "Reference" msgstr "" -#: build/models.py:138 +#: build/models.py:142 msgid "Brief description of the build" msgstr "" -#: build/models.py:147 build/templates/build/build_base.html:163 +#: build/models.py:151 build/templates/build/build_base.html:163 #: build/templates/build/detail.html:77 msgid "Parent Build" msgstr "" -#: build/models.py:148 +#: build/models.py:152 msgid "BuildOrder to which this build is allocated" msgstr "" -#: build/models.py:153 build/templates/build/auto_allocate.html:16 +#: build/models.py:157 build/templates/build/auto_allocate.html:16 #: build/templates/build/build_base.html:128 -#: build/templates/build/detail.html:26 company/models.py:622 -#: order/models.py:660 order/models.py:693 -#: order/templates/order/order_wizard/select_parts.html:30 -#: order/templates/order/purchase_order_detail.html:132 +#: build/templates/build/detail.html:26 company/models.py:689 +#: order/models.py:755 order/models.py:814 +#: order/templates/order/order_wizard/select_parts.html:32 +#: order/templates/order/purchase_order_detail.html:159 #: order/templates/order/receive_parts.html:19 -#: order/templates/order/sales_order_detail.html:213 part/models.py:321 -#: part/models.py:1967 part/models.py:1979 part/models.py:1997 -#: part/models.py:2072 part/models.py:2168 part/models.py:2254 -#: part/templates/part/part_app_base.html:8 -#: part/templates/part/part_pricing.html:9 part/templates/part/related.html:29 +#: order/templates/order/sales_order_detail.html:224 part/models.py:325 +#: part/models.py:1988 part/models.py:2004 part/models.py:2023 +#: part/models.py:2041 part/models.py:2120 part/models.py:2224 +#: part/models.py:2314 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 part/templates/part/related.html:29 #: part/templates/part/set_category.html:13 #: report/templates/report/inventree_build_order_base.html:110 #: report/templates/report/inventree_po_report.html:90 #: report/templates/report/inventree_so_report.html:90 #: templates/InvenTree/search.html:112 templates/InvenTree/search.html:210 #: templates/js/barcode.js:362 templates/js/bom.js:163 -#: templates/js/build.js:466 templates/js/build.js:751 -#: templates/js/build.js:991 templates/js/company.js:140 -#: templates/js/company.js:238 templates/js/part.js:241 -#: templates/js/part.js:404 templates/js/stock.js:521 -#: templates/js/stock.js:1346 +#: templates/js/build.js:552 templates/js/build.js:839 +#: templates/js/build.js:1079 templates/js/company.js:264 +#: templates/js/company.js:464 templates/js/part.js:241 +#: templates/js/part.js:404 templates/js/stock.js:526 +#: templates/js/stock.js:1385 msgid "Part" msgstr "" -#: build/models.py:161 +#: build/models.py:165 msgid "Select part to build" msgstr "" -#: build/models.py:166 +#: build/models.py:170 msgid "Sales Order Reference" msgstr "" -#: build/models.py:170 +#: build/models.py:174 msgid "SalesOrder to which this build is allocated" msgstr "" -#: build/models.py:175 +#: build/models.py:179 msgid "Source Location" msgstr "" -#: build/models.py:179 +#: build/models.py:183 msgid "Select location to take stock from for this build (leave blank to take from any stock location)" msgstr "" -#: build/models.py:184 +#: build/models.py:188 msgid "Destination Location" msgstr "" -#: build/models.py:188 +#: build/models.py:192 msgid "Select location where the completed items will be stored" msgstr "" -#: build/models.py:192 +#: build/models.py:196 msgid "Build Quantity" msgstr "" -#: build/models.py:195 +#: build/models.py:199 msgid "Number of stock items to build" msgstr "" -#: build/models.py:199 +#: build/models.py:203 msgid "Completed items" msgstr "" -#: build/models.py:201 +#: build/models.py:205 msgid "Number of stock items which have been completed" msgstr "" -#: build/models.py:205 part/templates/part/part_base.html:167 +#: build/models.py:209 part/templates/part/part_base.html:167 msgid "Build Status" msgstr "" -#: build/models.py:209 +#: build/models.py:213 msgid "Build status code" msgstr "" -#: build/models.py:213 stock/models.py:466 +#: build/models.py:217 stock/models.py:470 msgid "Batch Code" msgstr "" -#: build/models.py:217 +#: build/models.py:221 msgid "Batch code for this build output" msgstr "" -#: build/models.py:220 order/models.py:107 part/models.py:882 -#: part/templates/part/detail.html:126 templates/js/order.js:293 +#: build/models.py:224 order/models.py:158 part/models.py:876 +#: part/templates/part/detail.html:126 templates/js/order.js:360 msgid "Creation Date" msgstr "" -#: build/models.py:224 order/models.py:474 +#: build/models.py:228 order/models.py:551 msgid "Target completion date" msgstr "" -#: build/models.py:228 order/models.py:220 templates/js/build.js:798 +#: build/models.py:232 order/models.py:284 templates/js/build.js:886 msgid "Completion Date" msgstr "" -#: build/models.py:234 +#: build/models.py:238 msgid "completed by" msgstr "" -#: build/models.py:242 +#: build/models.py:246 msgid "Issued by" msgstr "" -#: build/models.py:243 +#: build/models.py:247 msgid "User who issued this build order" msgstr "" -#: build/models.py:251 build/templates/build/build_base.html:184 -#: build/templates/build/detail.html:105 order/models.py:121 +#: build/models.py:255 build/templates/build/build_base.html:184 +#: build/templates/build/detail.html:105 order/models.py:172 #: order/templates/order/order_base.html:138 -#: order/templates/order/sales_order_base.html:140 part/models.py:886 +#: order/templates/order/sales_order_base.html:140 part/models.py:880 #: report/templates/report/inventree_build_order_base.html:159 msgid "Responsible" msgstr "" -#: build/models.py:252 +#: build/models.py:256 msgid "User responsible for this build order" msgstr "" -#: build/models.py:257 build/templates/build/detail.html:91 +#: build/models.py:261 build/templates/build/detail.html:91 #: company/templates/company/manufacturer_part_base.html:79 #: company/templates/company/manufacturer_part_detail.html:28 #: company/templates/company/supplier_part_base.html:78 #: company/templates/company/supplier_part_detail.html:28 #: part/templates/part/detail.html:83 part/templates/part/part_base.html:94 -#: stock/models.py:460 stock/templates/stock/item_base.html:345 +#: stock/models.py:464 stock/templates/stock/item_base.html:345 msgid "External Link" msgstr "" -#: build/models.py:258 part/models.py:744 stock/models.py:462 +#: build/models.py:262 part/models.py:738 stock/models.py:466 msgid "Link to external URL" msgstr "" -#: build/models.py:262 build/templates/build/navbar.html:53 -#: company/models.py:132 company/models.py:498 +#: build/models.py:266 build/templates/build/navbar.html:53 +#: company/models.py:141 company/models.py:561 #: company/templates/company/navbar.html:70 -#: company/templates/company/navbar.html:73 order/models.py:125 -#: order/models.py:620 order/templates/order/po_navbar.html:29 -#: order/templates/order/po_navbar.html:32 -#: order/templates/order/purchase_order_detail.html:239 -#: order/templates/order/sales_order_detail.html:278 +#: company/templates/company/navbar.html:73 order/models.py:176 +#: order/models.py:711 order/templates/order/po_navbar.html:38 +#: order/templates/order/po_navbar.html:41 +#: order/templates/order/purchase_order_detail.html:270 +#: order/templates/order/sales_order_detail.html:319 #: order/templates/order/so_navbar.html:33 -#: order/templates/order/so_navbar.html:36 part/models.py:871 -#: part/templates/part/navbar.html:134 +#: order/templates/order/so_navbar.html:36 part/models.py:865 +#: part/templates/part/navbar.html:133 #: report/templates/report/inventree_build_order_base.html:173 -#: stock/forms.py:173 stock/forms.py:317 stock/forms.py:349 stock/forms.py:377 -#: stock/models.py:532 stock/models.py:1667 stock/models.py:1769 +#: stock/forms.py:140 stock/forms.py:284 stock/forms.py:316 stock/forms.py:344 +#: stock/models.py:536 stock/models.py:1678 stock/models.py:1784 #: stock/templates/stock/navbar.html:57 templates/js/barcode.js:37 -#: templates/js/bom.js:356 templates/js/stock.js:141 templates/js/stock.js:674 +#: templates/js/bom.js:349 templates/js/stock.js:141 templates/js/stock.js:713 msgid "Notes" msgstr "" -#: build/models.py:263 +#: build/models.py:267 msgid "Extra build notes" msgstr "" -#: build/models.py:740 +#: build/models.py:744 msgid "No build output specified" msgstr "" -#: build/models.py:743 +#: build/models.py:747 msgid "Build output is already completed" msgstr "" -#: build/models.py:746 +#: build/models.py:750 msgid "Build output does not match Build Order" msgstr "" -#: build/models.py:1152 +#: build/models.py:1160 msgid "BuildItem must be unique for build, stock_item and install_into" msgstr "" -#: build/models.py:1177 +#: build/models.py:1185 msgid "Build item must specify a build output, as master part is marked as trackable" msgstr "" -#: build/models.py:1181 +#: build/models.py:1189 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:1188 order/models.py:791 +#: build/models.py:1196 order/models.py:915 msgid "StockItem is over-allocated" msgstr "" -#: build/models.py:1192 order/models.py:794 +#: build/models.py:1200 order/models.py:918 msgid "Allocation quantity must be greater than zero" msgstr "" -#: build/models.py:1196 +#: build/models.py:1204 msgid "Quantity must be 1 for serialized stock" msgstr "" -#: build/models.py:1256 +#: build/models.py:1264 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:1316 stock/templates/stock/item_base.html:317 -#: templates/InvenTree/search.html:183 templates/js/build.js:724 +#: build/models.py:1324 stock/templates/stock/item_base.html:317 +#: templates/InvenTree/search.html:183 templates/js/build.js:812 #: templates/navbar.html:29 msgid "Build" msgstr "" -#: build/models.py:1317 +#: build/models.py:1325 msgid "Build to allocate parts" msgstr "" -#: build/models.py:1333 part/templates/part/allocation.html:18 -#: part/templates/part/allocation.html:24 -#: part/templates/part/allocation.html:31 -#: part/templates/part/allocation.html:49 -#: stock/templates/stock/item_base.html:8 +#: build/models.py:1341 stock/templates/stock/item_base.html:8 #: stock/templates/stock/item_base.html:31 #: stock/templates/stock/item_base.html:339 -#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:841 -#: templates/js/stock.js:1090 +#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:206 +#: templates/js/build.js:211 templates/js/build.js:929 +#: templates/js/order.js:433 templates/js/order.js:438 +#: templates/js/stock.js:1129 msgid "Stock Item" msgstr "" -#: build/models.py:1334 +#: build/models.py:1342 msgid "Source stock item" msgstr "" -#: build/models.py:1347 +#: build/models.py:1355 msgid "Stock quantity to allocate to build" msgstr "" -#: build/models.py:1355 +#: build/models.py:1363 msgid "Install into" msgstr "" -#: build/models.py:1356 +#: build/models.py:1364 msgid "Destination stock item" msgstr "" @@ -880,7 +885,7 @@ msgstr "" msgid "Auto Allocate" msgstr "" -#: build/templates/build/allocate.html:25 templates/js/build.js:656 +#: build/templates/build/allocate.html:25 templates/js/build.js:744 msgid "Unallocate stock" msgstr "" @@ -894,8 +899,8 @@ msgstr "" #: build/templates/build/allocate.html:30 #: company/templates/company/detail_manufacturer_part.html:33 -#: company/templates/company/detail_supplier_part.html:32 order/views.py:986 -#: part/templates/part/category.html:127 +#: company/templates/company/detail_supplier_part.html:32 order/views.py:724 +#: part/templates/part/category.html:136 msgid "Order Parts" msgstr "" @@ -913,23 +918,52 @@ msgstr "" #: build/templates/build/allocation_card.html:21 #: build/templates/build/complete_output.html:46 -#: order/templates/order/sales_order_detail.html:75 -#: order/templates/order/sales_order_detail.html:160 +#: order/templates/order/sales_order_detail.html:85 +#: order/templates/order/sales_order_detail.html:170 #: report/templates/report/inventree_test_report_base.html:75 -#: stock/models.py:454 stock/templates/stock/item_base.html:249 -#: templates/js/build.js:484 +#: stock/models.py:458 stock/templates/stock/item_base.html:249 +#: templates/js/build.js:570 templates/js/model_renderers.js:41 msgid "Serial Number" msgstr "" #: build/templates/build/attachments.html:12 #: build/templates/build/navbar.html:43 build/templates/build/navbar.html:46 -#: order/templates/order/po_navbar.html:26 -#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:125 -#: part/templates/part/navbar.html:128 stock/templates/stock/navbar.html:47 +#: order/templates/order/po_navbar.html:35 +#: order/templates/order/so_navbar.html:29 part/templates/part/navbar.html:124 +#: part/templates/part/navbar.html:127 stock/templates/stock/navbar.html:47 #: stock/templates/stock/navbar.html:50 msgid "Attachments" msgstr "" +#: build/templates/build/attachments.html:51 +#: order/templates/order/so_attachments.html:79 +#: part/templates/part/attachments.html:81 +#: stock/templates/stock/item_attachments.html:81 +#: templates/attachment_table.html:6 +msgid "Add Attachment" +msgstr "" + +#: build/templates/build/attachments.html:69 +#: order/templates/order/so_attachments.html:52 +#: part/templates/part/attachments.html:35 +#: stock/templates/stock/item_attachments.html:49 +msgid "Edit Attachment" +msgstr "" + +#: build/templates/build/attachments.html:76 +#: order/templates/order/so_attachments.html:58 +#: part/templates/part/attachments.html:44 +#: stock/templates/stock/item_attachments.html:58 +msgid "Confirm Delete Operation" +msgstr "" + +#: build/templates/build/attachments.html:77 +#: order/templates/order/so_attachments.html:59 +#: part/templates/part/attachments.html:45 +#: stock/templates/stock/item_attachments.html:59 +msgid "Delete Attachment" +msgstr "" + #: build/templates/build/auto_allocate.html:9 msgid "Automatically Allocate Stock" msgstr "" @@ -978,7 +1012,7 @@ msgstr "" #: company/templates/company/supplier_part_base.html:26 #: order/templates/order/order_base.html:26 #: order/templates/order/sales_order_base.html:37 -#: part/templates/part/category.html:18 part/templates/part/part_base.html:22 +#: part/templates/part/category.html:27 part/templates/part/part_base.html:22 #: stock/templates/stock/item_base.html:62 #: stock/templates/stock/location.html:31 msgid "Admin view" @@ -990,8 +1024,8 @@ msgstr "" #: order/templates/order/order_base.html:86 #: order/templates/order/sales_order_base.html:43 #: order/templates/order/sales_order_base.html:88 -#: templates/js/table_filters.js:245 templates/js/table_filters.js:264 -#: templates/js/table_filters.js:281 +#: templates/js/table_filters.js:250 templates/js/table_filters.js:269 +#: templates/js/table_filters.js:286 msgid "Overdue" msgstr "" @@ -1037,14 +1071,13 @@ msgid "Progress" msgstr "" #: build/templates/build/build_base.html:170 -#: build/templates/build/detail.html:84 order/models.py:691 +#: build/templates/build/detail.html:84 order/models.py:812 #: order/templates/order/sales_order_base.html:9 #: order/templates/order/sales_order_base.html:35 #: order/templates/order/sales_order_ship.html:25 -#: part/templates/part/allocation.html:30 #: report/templates/report/inventree_build_order_base.html:136 #: report/templates/report/inventree_so_report.html:77 -#: stock/templates/stock/item_base.html:279 templates/js/order.js:245 +#: stock/templates/stock/item_base.html:279 templates/js/order.js:307 msgid "Sales Order" msgstr "" @@ -1185,7 +1218,10 @@ msgstr "" msgid "Stock can be taken from any available location." msgstr "" -#: build/templates/build/detail.html:46 stock/forms.py:169 stock/forms.py:375 +#: build/templates/build/detail.html:46 order/forms.py:88 order/models.py:771 +#: order/templates/order/purchase_order_detail.html:266 +#: order/templates/order/receive_parts.html:25 stock/forms.py:136 +#: stock/forms.py:342 msgid "Destination" msgstr "" @@ -1194,15 +1230,15 @@ msgid "Destination location not specified" msgstr "" #: build/templates/build/detail.html:70 -#: stock/templates/stock/item_base.html:303 templates/js/stock.js:634 -#: templates/js/stock.js:1381 templates/js/table_filters.js:112 +#: stock/templates/stock/item_base.html:303 templates/js/stock.js:638 +#: templates/js/stock.js:1420 templates/js/table_filters.js:112 #: templates/js/table_filters.js:206 msgid "Batch" msgstr "" #: build/templates/build/detail.html:116 #: order/templates/order/order_base.html:111 -#: order/templates/order/sales_order_base.html:113 templates/js/build.js:788 +#: order/templates/order/sales_order_base.html:113 templates/js/build.js:876 msgid "Created" msgstr "" @@ -1210,7 +1246,7 @@ msgstr "" msgid "No target date set" msgstr "" -#: build/templates/build/detail.html:132 templates/js/build.js:766 +#: build/templates/build/detail.html:132 templates/js/build.js:854 msgid "Completed" msgstr "" @@ -1248,9 +1284,9 @@ msgstr "" #: build/templates/build/navbar.html:15 #: company/templates/company/navbar.html:15 -#: order/templates/order/po_navbar.html:14 -#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:15 -#: templates/js/stock.js:1019 +#: order/templates/order/po_navbar.html:15 +#: order/templates/order/so_navbar.html:15 part/templates/part/navbar.html:18 +#: templates/js/stock.js:1058 msgid "Details" msgstr "" @@ -1285,8 +1321,7 @@ msgstr "" #: build/templates/build/notes.html:26 company/templates/company/notes.html:24 #: order/templates/order/order_notes.html:27 #: order/templates/order/sales_order_notes.html:29 -#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:482 -#: stock/templates/stock/item_base.html:492 +#: part/templates/part/notes.html:27 stock/templates/stock/item_base.html:487 #: stock/templates/stock/item_notes.html:26 msgid "Save" msgstr "" @@ -1315,7 +1350,7 @@ msgstr "" msgid "Maximum output quantity is " msgstr "" -#: build/views.py:184 stock/views.py:1821 +#: build/views.py:184 stock/views.py:1653 msgid "Serial numbers already exist" msgstr "" @@ -1331,7 +1366,7 @@ msgstr "" msgid "Confirm unallocation of build stock" msgstr "" -#: build/views.py:281 build/views.py:371 stock/views.py:425 +#: build/views.py:281 build/views.py:371 stock/views.py:346 msgid "Check the confirmation box" msgstr "" @@ -1411,8 +1446,8 @@ msgstr "" msgid "Stock item is over-allocated" msgstr "" -#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:585 -#: templates/js/build.js:848 templates/js/build.js:1031 +#: build/views.py:872 templates/js/bom.js:230 templates/js/build.js:671 +#: templates/js/build.js:936 templates/js/build.js:1119 msgid "Available" msgstr "" @@ -1428,60 +1463,35 @@ msgstr "" msgid "Updated Build Item" msgstr "" -#: build/views.py:1070 -msgid "Add Build Order Attachment" -msgstr "" - -#: build/views.py:1083 order/views.py:115 order/views.py:167 part/views.py:173 -#: stock/views.py:277 -msgid "Added attachment" -msgstr "" - -#: build/views.py:1119 order/views.py:194 order/views.py:215 -msgid "Edit Attachment" -msgstr "" - -#: build/views.py:1129 order/views.py:198 order/views.py:219 -msgid "Attachment updated" -msgstr "" - -#: build/views.py:1139 order/views.py:234 order/views.py:248 -msgid "Delete Attachment" -msgstr "" - -#: build/views.py:1144 order/views.py:240 order/views.py:254 stock/views.py:333 -msgid "Deleted attachment" -msgstr "" - -#: common/files.py:64 +#: common/files.py:66 msgid "Unsupported file format: {ext.upper()}" msgstr "" -#: common/files.py:69 +#: common/files.py:71 msgid "Error reading file (invalid format)" msgstr "" -#: common/files.py:71 +#: common/files.py:73 msgid "Error reading file (incorrect dimension)" msgstr "" -#: common/files.py:73 +#: common/files.py:75 msgid "Error reading file (data could be corrupted)" msgstr "" -#: common/forms.py:39 templates/attachment_table.html:15 +#: common/forms.py:34 templates/js/attachment.js:42 msgid "File" msgstr "" -#: common/forms.py:40 +#: common/forms.py:35 msgid "Select file to upload" msgstr "" -#: common/forms.py:55 +#: common/forms.py:50 msgid "{name.title()} File" msgstr "" -#: common/forms.py:56 +#: common/forms.py:51 #, python-brace-format msgid "Select {name} file to upload" msgstr "" @@ -1502,7 +1512,7 @@ msgstr "" msgid "Use the instance name in the title-bar" msgstr "" -#: common/models.py:72 company/models.py:94 company/models.py:95 +#: common/models.py:72 company/models.py:99 company/models.py:100 msgid "Company name" msgstr "" @@ -1519,310 +1529,358 @@ msgid "Base URL for server instance" msgstr "" #: common/models.py:85 -msgid "Download from URL" +msgid "Default Currency" msgstr "" #: common/models.py:86 -msgid "Allow download of remote images and files from external URL" +msgid "Default currency" msgstr "" #: common/models.py:92 -msgid "Barcode Support" +msgid "Download from URL" msgstr "" #: common/models.py:93 -msgid "Enable barcode scanner support" +msgid "Allow download of remote images and files from external URL" msgstr "" #: common/models.py:99 -msgid "IPN Regex" +msgid "Barcode Support" msgstr "" #: common/models.py:100 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:106 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:107 msgid "Regular expression pattern for matching Part IPN" msgstr "" -#: common/models.py:104 +#: common/models.py:111 msgid "Allow Duplicate IPN" msgstr "" -#: common/models.py:105 +#: common/models.py:112 msgid "Allow multiple parts to share the same IPN" msgstr "" -#: common/models.py:111 +#: common/models.py:118 msgid "Allow Editing IPN" msgstr "" -#: common/models.py:112 +#: common/models.py:119 msgid "Allow changing the IPN value while editing a part" msgstr "" -#: common/models.py:118 +#: common/models.py:125 msgid "Copy Part BOM Data" msgstr "" -#: common/models.py:119 +#: common/models.py:126 msgid "Copy BOM data by default when duplicating a part" msgstr "" -#: common/models.py:125 +#: common/models.py:132 msgid "Copy Part Parameter Data" msgstr "" -#: common/models.py:126 +#: common/models.py:133 msgid "Copy parameter data by default when duplicating a part" msgstr "" -#: common/models.py:132 +#: common/models.py:139 msgid "Copy Part Test Data" msgstr "" -#: common/models.py:133 +#: common/models.py:140 msgid "Copy test data by default when duplicating a part" msgstr "" -#: common/models.py:139 +#: common/models.py:146 msgid "Copy Category Parameter Templates" msgstr "" -#: common/models.py:140 +#: common/models.py:147 msgid "Copy category parameter templates when creating a part" msgstr "" -#: common/models.py:146 +#: common/models.py:153 msgid "Recent Part Count" msgstr "" -#: common/models.py:147 +#: common/models.py:154 msgid "Number of recent parts to display on index page" msgstr "" -#: common/models.py:153 part/models.py:2170 part/templates/part/detail.html:160 -#: report/models.py:185 stock/forms.py:259 templates/js/table_filters.js:25 -#: templates/js/table_filters.js:315 +#: common/models.py:160 part/models.py:2226 part/templates/part/detail.html:160 +#: report/models.py:186 stock/forms.py:226 templates/js/table_filters.js:25 +#: templates/js/table_filters.js:320 msgid "Template" msgstr "" -#: common/models.py:154 +#: common/models.py:161 msgid "Parts are templates by default" msgstr "" -#: common/models.py:160 part/models.py:834 part/templates/part/detail.html:170 -#: templates/js/table_filters.js:128 templates/js/table_filters.js:327 +#: common/models.py:167 part/models.py:828 part/templates/part/detail.html:170 +#: templates/js/table_filters.js:128 templates/js/table_filters.js:332 msgid "Assembly" msgstr "" -#: common/models.py:161 +#: common/models.py:168 msgid "Parts can be assembled from other components by default" msgstr "" -#: common/models.py:167 part/models.py:840 part/templates/part/detail.html:180 -#: templates/js/table_filters.js:331 +#: common/models.py:174 part/models.py:834 part/templates/part/detail.html:180 +#: templates/js/table_filters.js:336 msgid "Component" msgstr "" -#: common/models.py:168 +#: common/models.py:175 msgid "Parts can be used as sub-components by default" msgstr "" -#: common/models.py:174 part/models.py:851 part/templates/part/detail.html:200 +#: common/models.py:181 part/models.py:845 part/templates/part/detail.html:200 msgid "Purchaseable" msgstr "" -#: common/models.py:175 +#: common/models.py:182 msgid "Parts are purchaseable by default" msgstr "" -#: common/models.py:181 part/models.py:856 part/templates/part/detail.html:210 -#: templates/js/table_filters.js:339 +#: common/models.py:188 part/models.py:850 part/templates/part/detail.html:210 +#: templates/js/table_filters.js:344 msgid "Salable" msgstr "" -#: common/models.py:182 +#: common/models.py:189 msgid "Parts are salable by default" msgstr "" -#: common/models.py:188 part/models.py:846 part/templates/part/detail.html:190 -#: templates/js/table_filters.js:33 templates/js/table_filters.js:343 +#: common/models.py:195 part/models.py:840 part/templates/part/detail.html:190 +#: templates/js/table_filters.js:33 templates/js/table_filters.js:348 msgid "Trackable" msgstr "" -#: common/models.py:189 +#: common/models.py:196 msgid "Parts are trackable by default" msgstr "" -#: common/models.py:195 part/models.py:866 part/templates/part/detail.html:150 +#: common/models.py:202 part/models.py:860 part/templates/part/detail.html:150 #: templates/js/table_filters.js:29 msgid "Virtual" msgstr "" -#: common/models.py:196 +#: common/models.py:203 msgid "Parts are virtual by default" msgstr "" -#: common/models.py:202 +#: common/models.py:209 msgid "Show Quantity in Forms" msgstr "" -#: common/models.py:203 +#: common/models.py:210 msgid "Display available part quantity in some forms" msgstr "" -#: common/models.py:209 templates/stats.html:25 -msgid "Debug Mode" -msgstr "" - -#: common/models.py:210 -msgid "Generate reports in debug mode (HTML output)" -msgstr "" - #: common/models.py:216 -msgid "Page Size" +msgid "Show Import in Views" msgstr "" #: common/models.py:217 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:223 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:224 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:230 +msgid "Show related parts" +msgstr "" + +#: common/models.py:231 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:237 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:238 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:244 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:245 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:251 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:252 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:258 +msgid "Page Size" +msgstr "" + +#: common/models.py:259 msgid "Default page size for PDF reports" msgstr "" -#: common/models.py:227 +#: common/models.py:269 msgid "Test Reports" msgstr "" -#: common/models.py:228 +#: common/models.py:270 msgid "Enable generation of test reports" msgstr "" -#: common/models.py:234 +#: common/models.py:276 msgid "Stock Expiry" msgstr "" -#: common/models.py:235 +#: common/models.py:277 msgid "Enable stock expiry functionality" msgstr "" -#: common/models.py:241 +#: common/models.py:283 msgid "Sell Expired Stock" msgstr "" -#: common/models.py:242 +#: common/models.py:284 msgid "Allow sale of expired stock" msgstr "" -#: common/models.py:248 +#: common/models.py:290 msgid "Stock Stale Time" msgstr "" -#: common/models.py:249 +#: common/models.py:291 msgid "Number of days stock items are considered stale before expiring" msgstr "" -#: common/models.py:251 part/templates/part/detail.html:121 +#: common/models.py:293 part/templates/part/detail.html:121 msgid "days" msgstr "" -#: common/models.py:256 +#: common/models.py:298 msgid "Build Expired Stock" msgstr "" -#: common/models.py:257 +#: common/models.py:299 msgid "Allow building with expired stock" msgstr "" -#: common/models.py:263 +#: common/models.py:305 msgid "Stock Ownership Control" msgstr "" -#: common/models.py:264 +#: common/models.py:306 msgid "Enable ownership control over stock locations and items" msgstr "" -#: common/models.py:270 +#: common/models.py:312 msgid "Group by Part" msgstr "" -#: common/models.py:271 +#: common/models.py:313 msgid "Group stock items by part reference in table views" msgstr "" -#: common/models.py:277 +#: common/models.py:319 msgid "Recent Stock Count" msgstr "" -#: common/models.py:278 +#: common/models.py:320 msgid "Number of recent stock items to display on index page" msgstr "" -#: common/models.py:284 +#: common/models.py:326 msgid "Build Order Reference Prefix" msgstr "" -#: common/models.py:285 +#: common/models.py:327 msgid "Prefix value for build order reference" msgstr "" -#: common/models.py:290 +#: common/models.py:332 msgid "Build Order Reference Regex" msgstr "" -#: common/models.py:291 +#: common/models.py:333 msgid "Regular expression pattern for matching build order reference" msgstr "" -#: common/models.py:295 +#: common/models.py:337 msgid "Sales Order Reference Prefix" msgstr "" -#: common/models.py:296 +#: common/models.py:338 msgid "Prefix value for sales order reference" msgstr "" -#: common/models.py:301 +#: common/models.py:343 msgid "Purchase Order Reference Prefix" msgstr "" -#: common/models.py:302 +#: common/models.py:344 msgid "Prefix value for purchase order reference" msgstr "" -#: common/models.py:525 +#: common/models.py:567 msgid "Settings key (must be unique - case insensitive" msgstr "" -#: common/models.py:527 +#: common/models.py:569 msgid "Settings value" msgstr "" -#: common/models.py:562 +#: common/models.py:604 msgid "Must be an integer value" msgstr "" -#: common/models.py:585 +#: common/models.py:627 msgid "Value must be a boolean value" msgstr "" -#: common/models.py:596 +#: common/models.py:638 msgid "Value must be an integer value" msgstr "" -#: common/models.py:619 +#: common/models.py:661 msgid "Key string must be unique" msgstr "" -#: common/models.py:700 company/forms.py:177 +#: common/models.py:742 company/forms.py:125 msgid "Price break quantity" msgstr "" -#: common/models.py:708 company/templates/company/supplier_part_pricing.html:82 -#: part/templates/part/sale_prices.html:90 templates/js/bom.js:271 +#: common/models.py:749 company/templates/company/supplier_part_pricing.html:84 +#: templates/js/part.js:832 msgid "Price" msgstr "" -#: common/models.py:709 +#: common/models.py:750 msgid "Unit price at specified quantity" msgstr "" -#: common/models.py:798 +#: common/models.py:842 msgid "Default" msgstr "" @@ -1830,25 +1888,30 @@ msgstr "" msgid "Current value" msgstr "" -#: common/views.py:32 +#: common/views.py:33 msgid "Change Setting" msgstr "" -#: common/views.py:101 +#: common/views.py:102 msgid "Supplied value is not allowed" msgstr "" -#: common/views.py:110 +#: common/views.py:111 msgid "Supplied value must be a boolean" msgstr "" #: common/views.py:184 order/templates/order/order_wizard/po_upload.html:42 -#: order/views.py:582 part/templates/part/bom_upload/upload_file.html:27 +#: order/templates/order/po_navbar.html:19 +#: order/templates/order/po_navbar.html:22 order/views.py:337 +#: part/templates/part/bom_upload/upload_file.html:27 +#: part/templates/part/import_wizard/part_upload.html:45 part/views.py:621 msgid "Upload File" msgstr "" #: common/views.py:185 order/templates/order/order_wizard/match_fields.html:52 -#: order/views.py:583 part/templates/part/bom_upload/select_fields.html:58 +#: order/views.py:338 part/templates/part/bom_upload/select_fields.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/templates/part/import_wizard/match_fields.html:52 part/views.py:622 msgid "Match Fields" msgstr "" @@ -1856,257 +1919,303 @@ msgstr "" msgid "Match Items" msgstr "" -#: common/views.py:479 +#: common/views.py:531 msgid "Fields matching failed" msgstr "" -#: company/forms.py:38 company/models.py:142 -#: company/templates/company/detail.html:42 -msgid "Currency" +#: common/views.py:586 +msgid "Parts imported" msgstr "" -#: company/forms.py:39 company/models.py:144 -msgid "Default currency used for this company" +#: common/views.py:608 order/templates/order/order_wizard/match_fields.html:27 +#: order/templates/order/order_wizard/match_parts.html:19 +#: order/templates/order/order_wizard/po_upload.html:40 +#: part/templates/part/import_wizard/match_fields.html:27 +#: part/templates/part/import_wizard/match_references.html:19 +#: part/templates/part/import_wizard/part_upload.html:43 +msgid "Previous Step" msgstr "" -#: company/forms.py:77 part/forms.py:46 +#: company/forms.py:26 part/forms.py:46 msgid "URL" msgstr "" -#: company/forms.py:78 part/forms.py:47 +#: company/forms.py:27 part/forms.py:47 msgid "Image URL" msgstr "" -#: company/forms.py:118 templates/js/part.js:786 +#: company/forms.py:67 templates/js/part.js:940 msgid "Single Price" msgstr "" -#: company/forms.py:120 +#: company/forms.py:68 msgid "Single quantity price" msgstr "" -#: company/forms.py:128 company/models.py:321 +#: company/forms.py:76 company/models.py:335 msgid "Select manufacturer" msgstr "" -#: company/forms.py:134 company/models.py:328 +#: company/forms.py:82 company/models.py:342 msgid "Manufacturer Part Number" msgstr "" -#: company/forms.py:136 company/models.py:327 +#: company/forms.py:84 company/models.py:341 #: company/templates/company/manufacturer_part_base.html:89 #: company/templates/company/manufacturer_part_detail.html:26 #: company/templates/company/supplier_part_base.html:102 #: company/templates/company/supplier_part_detail.html:35 -#: order/templates/order/purchase_order_detail.html:162 part/bom.py:171 -#: part/bom.py:242 templates/js/company.js:181 templates/js/company.js:307 +#: order/templates/order/purchase_order_detail.html:189 part/bom.py:171 +#: part/bom.py:242 templates/js/company.js:305 templates/js/company.js:533 msgid "MPN" msgstr "" -#: company/models.py:99 +#: company/models.py:104 msgid "Company description" msgstr "" -#: company/models.py:100 +#: company/models.py:105 msgid "Description of the company" msgstr "" -#: company/models.py:104 company/templates/company/company_base.html:70 -#: company/templates/company/detail.html:33 templates/js/company.js:60 +#: company/models.py:111 company/templates/company/company_base.html:70 +#: company/templates/company/detail.html:33 templates/js/company.js:129 msgid "Website" msgstr "" -#: company/models.py:104 +#: company/models.py:112 msgid "Company website URL" msgstr "" -#: company/models.py:107 company/templates/company/company_base.html:77 +#: company/models.py:116 company/templates/company/company_base.html:77 msgid "Address" msgstr "" -#: company/models.py:108 +#: company/models.py:117 msgid "Company address" msgstr "" -#: company/models.py:111 +#: company/models.py:120 msgid "Phone number" msgstr "" -#: company/models.py:112 +#: company/models.py:121 msgid "Contact phone number" msgstr "" -#: company/models.py:115 company/templates/company/company_base.html:91 +#: company/models.py:124 company/templates/company/company_base.html:91 msgid "Email" msgstr "" -#: company/models.py:115 +#: company/models.py:124 msgid "Contact email address" msgstr "" -#: company/models.py:118 company/templates/company/company_base.html:98 +#: company/models.py:127 company/templates/company/company_base.html:98 msgid "Contact" msgstr "" -#: company/models.py:119 +#: company/models.py:128 msgid "Point of contact" msgstr "" -#: company/models.py:121 company/models.py:333 company/models.py:485 -#: order/models.py:105 part/models.py:743 +#: company/models.py:130 company/models.py:347 company/models.py:548 +#: order/models.py:156 part/models.py:737 #: report/templates/report/inventree_build_order_base.html:165 -#: templates/js/company.js:188 templates/js/company.js:318 -#: templates/js/part.js:497 +#: templates/js/company.js:312 templates/js/company.js:544 +#: templates/js/part.js:498 msgid "Link" msgstr "" -#: company/models.py:121 +#: company/models.py:130 msgid "Link to external company information" msgstr "" -#: company/models.py:129 part/models.py:753 +#: company/models.py:138 part/models.py:747 msgid "Image" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "is customer" msgstr "" -#: company/models.py:134 +#: company/models.py:143 msgid "Do you sell items to this company?" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "is supplier" msgstr "" -#: company/models.py:136 +#: company/models.py:145 msgid "Do you purchase items from this company?" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "is manufacturer" msgstr "" -#: company/models.py:138 +#: company/models.py:147 msgid "Does this company manufacture parts?" msgstr "" -#: company/models.py:305 company/models.py:456 stock/models.py:407 +#: company/models.py:151 company/serializers.py:259 +#: company/templates/company/detail.html:42 +msgid "Currency" +msgstr "" + +#: company/models.py:154 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:319 company/models.py:519 stock/models.py:411 #: stock/templates/stock/item_base.html:235 msgid "Base Part" msgstr "" -#: company/models.py:309 company/models.py:460 order/views.py:1587 +#: company/models.py:323 company/models.py:523 order/views.py:1127 msgid "Select part" msgstr "" -#: company/models.py:320 company/templates/company/detail.html:57 +#: company/models.py:334 company/templates/company/detail.html:57 #: company/templates/company/manufacturer_part_base.html:85 #: company/templates/company/manufacturer_part_detail.html:25 #: company/templates/company/supplier_part_base.html:94 #: company/templates/company/supplier_part_detail.html:34 part/bom.py:170 #: part/bom.py:241 stock/templates/stock/item_base.html:352 -#: templates/js/company.js:44 templates/js/company.js:165 -#: templates/js/company.js:289 +#: templates/js/company.js:113 templates/js/company.js:289 +#: templates/js/company.js:515 msgid "Manufacturer" msgstr "" -#: company/models.py:334 +#: company/models.py:348 msgid "URL for external manufacturer part link" msgstr "" -#: company/models.py:340 +#: company/models.py:354 msgid "Manufacturer part description" msgstr "" -#: company/models.py:466 company/templates/company/detail.html:62 +#: company/models.py:408 company/models.py:542 +#: company/templates/company/manufacturer_part_base.html:6 +#: company/templates/company/manufacturer_part_base.html:19 +#: stock/templates/stock/item_base.html:362 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:415 +msgid "Parameter name" +msgstr "" + +#: company/models.py:421 part/templates/part/params.html:28 +#: report/templates/report/inventree_test_report_base.html:90 +#: stock/models.py:1771 templates/InvenTree/settings/header.html:8 +#: templates/js/company.js:365 templates/js/stock.js:137 +msgid "Value" +msgstr "" + +#: company/models.py:422 +msgid "Parameter value" +msgstr "" + +#: company/models.py:428 part/models.py:822 part/models.py:2194 +#: part/templates/part/detail.html:106 part/templates/part/params.html:29 +#: templates/js/company.js:371 +msgid "Units" +msgstr "" + +#: company/models.py:429 +msgid "Parameter units" +msgstr "" + +#: company/models.py:529 company/templates/company/detail.html:62 #: company/templates/company/supplier_part_base.html:84 -#: company/templates/company/supplier_part_detail.html:25 order/models.py:192 +#: company/templates/company/supplier_part_detail.html:25 order/models.py:256 #: order/templates/order/order_base.html:92 #: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:175 -#: part/bom.py:286 stock/templates/stock/item_base.html:364 -#: templates/js/company.js:48 templates/js/company.js:263 -#: templates/js/order.js:170 +#: part/bom.py:286 stock/templates/stock/item_base.html:369 +#: templates/js/company.js:117 templates/js/company.js:489 +#: templates/js/order.js:232 msgid "Supplier" msgstr "" -#: company/models.py:467 +#: company/models.py:530 msgid "Select supplier" msgstr "" -#: company/models.py:472 company/templates/company/supplier_part_base.html:88 +#: company/models.py:535 company/templates/company/supplier_part_base.html:88 #: company/templates/company/supplier_part_detail.html:26 -#: order/templates/order/purchase_order_detail.html:153 part/bom.py:176 +#: order/templates/order/purchase_order_detail.html:180 part/bom.py:176 #: part/bom.py:287 msgid "SKU" msgstr "" -#: company/models.py:473 +#: company/models.py:536 msgid "Supplier stock keeping unit" msgstr "" -#: company/models.py:479 -#: company/templates/company/manufacturer_part_base.html:6 -#: company/templates/company/manufacturer_part_base.html:19 -#: stock/templates/stock/item_base.html:357 -msgid "Manufacturer Part" -msgstr "" - -#: company/models.py:480 +#: company/models.py:543 msgid "Select manufacturer part" msgstr "" -#: company/models.py:486 +#: company/models.py:549 msgid "URL for external supplier part link" msgstr "" -#: company/models.py:492 +#: company/models.py:555 msgid "Supplier part description" msgstr "" -#: company/models.py:497 company/templates/company/supplier_part_base.html:116 -#: company/templates/company/supplier_part_detail.html:38 part/models.py:2282 +#: company/models.py:560 company/templates/company/supplier_part_base.html:116 +#: company/templates/company/supplier_part_detail.html:38 part/models.py:2342 #: report/templates/report/inventree_po_report.html:93 #: report/templates/report/inventree_so_report.html:93 msgid "Note" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "base cost" msgstr "" -#: company/models.py:501 part/models.py:1614 +#: company/models.py:564 part/models.py:1615 msgid "Minimum charge (e.g. stocking fee)" msgstr "" -#: company/models.py:503 company/templates/company/supplier_part_base.html:109 -#: stock/models.py:431 stock/templates/stock/item_base.html:310 -#: templates/js/stock.js:670 +#: company/models.py:566 company/templates/company/supplier_part_base.html:109 +#: stock/models.py:435 stock/templates/stock/item_base.html:310 +#: templates/js/stock.js:709 msgid "Packaging" msgstr "" -#: company/models.py:503 +#: company/models.py:566 msgid "Part packaging" msgstr "" -#: company/models.py:505 part/models.py:1616 +#: company/models.py:568 part/models.py:1617 msgid "multiple" msgstr "" -#: company/models.py:505 +#: company/models.py:568 msgid "Order multiple" msgstr "" +#: company/serializers.py:68 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:69 +msgid "Currency Code" +msgstr "" + #: company/templates/company/assigned_stock.html:10 #: company/templates/company/navbar.html:62 -#: company/templates/company/navbar.html:65 templates/js/build.js:477 +#: company/templates/company/navbar.html:65 templates/js/build.js:563 msgid "Assigned Stock" msgstr "" #: company/templates/company/company_base.html:9 #: company/templates/company/company_base.html:35 -#: templates/InvenTree/search.html:304 templates/js/company.js:33 +#: templates/InvenTree/search.html:304 templates/js/company.js:102 msgid "Company" msgstr "" @@ -2120,7 +2229,7 @@ msgstr "" msgid "Download image from URL" msgstr "" -#: company/templates/company/company_base.html:46 order/views.py:311 +#: company/templates/company/company_base.html:46 templates/js/order.js:61 msgid "Create Purchase Order" msgstr "" @@ -2128,7 +2237,8 @@ msgstr "" msgid "Edit company information" msgstr "" -#: company/templates/company/company_base.html:56 company/views.py:326 +#: company/templates/company/company_base.html:56 +#: company/templates/company/company_base.html:126 msgid "Delete Company" msgstr "" @@ -2142,15 +2252,9 @@ msgstr "" msgid "Phone" msgstr "" -#: company/templates/company/delete.html:7 -#, python-format -msgid "Are you sure you want to delete company '%(name)s'?" -msgstr "" - -#: company/templates/company/delete.html:12 -#, python-format -msgid "There are %(count)s parts sourced from this company.
                \n" -"If this supplier is deleted, these supplier part entries will also be deleted." +#: company/templates/company/company_base.html:166 +#: part/templates/part/part_base.html:307 +msgid "Upload Image" msgstr "" #: company/templates/company/detail.html:21 @@ -2165,11 +2269,11 @@ msgstr "" msgid "Uses default currency" msgstr "" -#: company/templates/company/detail.html:67 order/models.py:463 -#: order/templates/order/sales_order_base.html:94 stock/models.py:449 -#: stock/models.py:450 stock/templates/stock/item_base.html:262 -#: templates/js/company.js:40 templates/js/order.js:267 -#: templates/js/stock.js:1072 +#: company/templates/company/detail.html:67 order/models.py:540 +#: order/templates/order/sales_order_base.html:94 stock/models.py:453 +#: stock/models.py:454 stock/templates/stock/item_base.html:262 +#: templates/js/company.js:109 templates/js/order.js:329 +#: templates/js/stock.js:1111 msgid "Customer" msgstr "" @@ -2190,7 +2294,8 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:28 #: company/templates/company/detail_supplier_part.html:27 #: company/templates/company/manufacturer_part_suppliers.html:20 -#: part/templates/part/category.html:122 +#: company/templates/company/manufacturer_part_suppliers.html:46 +#: part/templates/part/category.html:131 #: part/templates/part/manufacturer.html:22 #: part/templates/part/supplier.html:20 msgid "Options" @@ -2198,7 +2303,7 @@ msgstr "" #: company/templates/company/detail_manufacturer_part.html:33 #: company/templates/company/detail_supplier_part.html:32 -#: part/templates/part/category.html:127 +#: part/templates/part/category.html:136 msgid "Order parts" msgstr "" @@ -2212,26 +2317,25 @@ msgstr "" msgid "Delete Parts" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:66 +#: company/templates/company/detail_manufacturer_part.html:68 #: company/templates/company/detail_supplier_part.html:66 -#: part/templates/part/bom.html:159 part/templates/part/category.html:118 -#: templates/js/stock.js:1287 +#: part/templates/part/bom.html:159 part/templates/part/category.html:127 +#: templates/js/stock.js:1326 msgid "New Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:67 +#: company/templates/company/detail_manufacturer_part.html:69 #: company/templates/company/detail_supplier_part.html:67 msgid "Create new Part" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:72 -#: company/views.py:71 part/templates/part/manufacturer.html:52 -#: part/templates/part/supplier.html:56 +#: company/templates/company/detail_manufacturer_part.html:74 +#: company/views.py:66 part/templates/part/manufacturer.html:52 +#: part/templates/part/supplier.html:55 msgid "New Manufacturer" msgstr "" -#: company/templates/company/detail_manufacturer_part.html:73 -#: company/views.py:284 +#: company/templates/company/detail_manufacturer_part.html:75 msgid "Create new Manufacturer" msgstr "" @@ -2241,40 +2345,37 @@ msgstr "" #: company/templates/company/detail_stock.html:37 #: company/templates/company/supplier_part_stock.html:34 -#: part/templates/part/category.html:114 part/templates/part/category.html:128 -#: part/templates/part/stock.html:54 stock/templates/stock/location.html:163 +#: part/templates/part/category.html:123 part/templates/part/category.html:137 +#: part/templates/part/stock.html:55 stock/templates/stock/location.html:163 msgid "Export" msgstr "" #: company/templates/company/detail_supplier_part.html:11 #: company/templates/company/manufacturer_part_navbar.html:11 -#: company/templates/company/manufacturer_part_suppliers.html:10 #: templates/InvenTree/search.html:164 msgid "Supplier Parts" msgstr "" #: company/templates/company/detail_supplier_part.html:21 -#: order/templates/order/order_wizard/select_parts.html:42 -#: order/templates/order/purchase_order_detail.html:50 +#: order/templates/order/order_wizard/select_parts.html:44 +#: part/templates/part/part_base.html:429 msgid "Create new supplier part" msgstr "" #: company/templates/company/detail_supplier_part.html:22 #: company/templates/company/manufacturer_part_suppliers.html:17 -#: order/templates/order/purchase_order_detail.html:49 -#: part/templates/part/supplier.html:17 templates/js/stock.js:1293 +#: part/templates/part/part_base.html:428 part/templates/part/supplier.html:17 +#: templates/js/stock.js:1332 msgid "New Supplier Part" msgstr "" #: company/templates/company/detail_supplier_part.html:72 -#: company/templates/company/manufacturer_part_suppliers.html:47 -#: company/views.py:64 order/templates/order/purchase_orders.html:185 -#: part/templates/part/supplier.html:50 +#: company/templates/company/manufacturer_part_suppliers.html:96 +#: company/views.py:60 part/templates/part/supplier.html:50 msgid "New Supplier" msgstr "" -#: company/templates/company/detail_supplier_part.html:73 company/views.py:281 -#: order/templates/order/purchase_orders.html:186 +#: company/templates/company/detail_supplier_part.html:73 msgid "Create new Supplier" msgstr "" @@ -2309,19 +2410,19 @@ msgstr "" msgid "Internal Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:6 -msgid "Are you sure you want to delete the following Manufacturer Parts?" +#: company/templates/company/manufacturer_part_base.html:125 +msgid "Edit Manufacturer Part" msgstr "" -#: company/templates/company/manufacturer_part_delete.html:36 -#, python-format -msgid "There are %(count)s suppliers defined for this manufacturer part. If you delete it, the following supplier parts will also be deleted:" +#: company/templates/company/manufacturer_part_base.html:134 +msgid "Delete Manufacturer Part" msgstr "" #: company/templates/company/manufacturer_part_navbar.html:14 -#: company/views.py:63 part/templates/part/navbar.html:84 -#: part/templates/part/navbar.html:87 templates/InvenTree/search.html:316 -#: templates/navbar.html:35 +#: company/templates/company/manufacturer_part_suppliers.html:10 +#: company/views.py:59 part/templates/part/navbar.html:87 +#: part/templates/part/navbar.html:90 part/templates/part/prices.html:153 +#: templates/InvenTree/search.html:316 templates/navbar.html:35 msgid "Suppliers" msgstr "" @@ -2332,13 +2433,13 @@ msgstr "" #: company/templates/company/manufacturer_part_navbar.html:22 #: company/templates/company/navbar.html:41 #: company/templates/company/supplier_part_navbar.html:15 -#: part/templates/part/navbar.html:36 stock/api.py:54 +#: part/templates/part/navbar.html:39 stock/api.py:53 #: stock/templates/stock/loc_link.html:7 stock/templates/stock/location.html:36 #: stock/templates/stock/stock_app_base.html:10 #: templates/InvenTree/index.html:128 templates/InvenTree/search.html:196 #: templates/InvenTree/search.html:232 #: templates/InvenTree/settings/tabs.html:31 templates/js/part.js:181 -#: templates/js/part.js:305 templates/js/part.js:464 templates/js/stock.js:561 +#: templates/js/part.js:305 templates/js/part.js:465 templates/js/stock.js:566 #: templates/navbar.html:26 msgid "Stock" msgstr "" @@ -2358,17 +2459,49 @@ msgid "Delete supplier parts" msgstr "" #: company/templates/company/manufacturer_part_suppliers.html:22 +#: company/templates/company/manufacturer_part_suppliers.html:48 +#: company/templates/company/manufacturer_part_suppliers.html:142 #: part/templates/part/manufacturer.html:24 part/templates/part/params.html:44 #: part/templates/part/related.html:44 part/templates/part/supplier.html:22 -#: stock/views.py:1002 users/models.py:187 +#: stock/views.py:855 templates/js/company.js:203 users/models.py:192 msgid "Delete" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:37 +#: part/templates/part/category_navbar.html:46 +#: part/templates/part/category_navbar.html:49 +#: part/templates/part/navbar.html:25 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:43 +#: part/templates/part/params.html:18 +#: templates/InvenTree/settings/category.html:29 +#: templates/InvenTree/settings/part.html:65 +msgid "New Parameter" +msgstr "" + #: company/templates/company/manufacturer_part_suppliers.html:48 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:80 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:97 #: part/templates/part/supplier.html:51 msgid "Create new supplier" msgstr "" +#: company/templates/company/manufacturer_part_suppliers.html:127 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part_suppliers.html:139 +msgid "Delete Parameters" +msgstr "" + #: company/templates/company/navbar.html:20 #: company/templates/company/navbar.html:23 msgid "Manufactured Parts" @@ -2379,14 +2512,14 @@ msgstr "" msgid "Supplied Parts" msgstr "" -#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:33 +#: company/templates/company/navbar.html:38 part/templates/part/navbar.html:36 #: stock/templates/stock/location.html:107 #: stock/templates/stock/location.html:122 #: stock/templates/stock/location.html:136 #: stock/templates/stock/location_navbar.html:22 #: stock/templates/stock/location_navbar.html:29 -#: templates/InvenTree/search.html:198 templates/js/stock.js:971 -#: templates/stats.html:93 templates/stats.html:102 users/models.py:42 +#: templates/InvenTree/search.html:198 templates/js/stock.js:1010 +#: templates/stats.html:93 templates/stats.html:102 users/models.py:43 msgid "Stock Items" msgstr "" @@ -2396,11 +2529,11 @@ msgstr "" #: company/templates/company/sales_orders.html:11 #: order/templates/order/sales_orders.html:8 #: order/templates/order/sales_orders.html:13 -#: part/templates/part/navbar.html:104 part/templates/part/navbar.html:107 -#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:228 +#: part/templates/part/navbar.html:101 part/templates/part/navbar.html:104 +#: part/templates/part/sales_orders.html:10 templates/InvenTree/index.html:236 #: templates/InvenTree/search.html:345 #: templates/InvenTree/settings/tabs.html:40 templates/navbar.html:46 -#: users/models.py:45 +#: users/models.py:46 msgid "Sales Orders" msgstr "" @@ -2408,11 +2541,11 @@ msgstr "" #: company/templates/company/purchase_orders.html:10 #: order/templates/order/purchase_orders.html:8 #: order/templates/order/purchase_orders.html:13 -#: part/templates/part/navbar.html:90 part/templates/part/navbar.html:93 -#: part/templates/part/orders.html:10 templates/InvenTree/index.html:205 +#: part/templates/part/navbar.html:93 part/templates/part/navbar.html:96 +#: part/templates/part/orders.html:10 templates/InvenTree/index.html:213 #: templates/InvenTree/search.html:325 #: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:37 -#: users/models.py:44 +#: users/models.py:45 msgid "Purchase Orders" msgstr "" @@ -2441,8 +2574,9 @@ msgid "New Sales Order" msgstr "" #: company/templates/company/supplier_part_base.html:7 -#: company/templates/company/supplier_part_base.html:20 stock/models.py:416 -#: stock/templates/stock/item_base.html:369 templates/js/company.js:279 +#: company/templates/company/supplier_part_base.html:20 stock/models.py:420 +#: stock/templates/stock/item_base.html:374 templates/js/company.js:505 +#: templates/js/stock.js:690 msgid "Supplier Part" msgstr "" @@ -2487,449 +2621,401 @@ msgid "Order Part" msgstr "" #: company/templates/company/supplier_part_pricing.html:11 +#: part/templates/part/navbar.html:74 msgid "Pricing Information" msgstr "" -#: company/templates/company/supplier_part_pricing.html:19 company/views.py:794 -#: part/templates/part/sale_prices.html:17 part/views.py:2733 +#: company/templates/company/supplier_part_pricing.html:19 +#: company/templates/company/supplier_part_pricing.html:118 +#: part/templates/part/prices.html:264 part/views.py:2788 msgid "Add Price Break" msgstr "" #: company/templates/company/supplier_part_pricing.html:38 -#: part/templates/part/sale_prices.html:46 msgid "No price break information found" msgstr "" -#: company/templates/company/supplier_part_pricing.html:89 -#: part/templates/part/sale_prices.html:97 +#: company/templates/company/supplier_part_pricing.html:52 part/views.py:2850 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:66 part/views.py:2836 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part_pricing.html:91 msgid "Edit price break" msgstr "" -#: company/templates/company/supplier_part_pricing.html:90 -#: part/templates/part/sale_prices.html:98 +#: company/templates/company/supplier_part_pricing.html:92 msgid "Delete price break" msgstr "" -#: company/views.py:70 part/templates/part/navbar.html:78 -#: part/templates/part/navbar.html:81 templates/InvenTree/search.html:306 -#: templates/navbar.html:36 +#: company/views.py:65 part/templates/part/navbar.html:81 +#: part/templates/part/navbar.html:84 part/templates/part/prices.html:157 +#: templates/InvenTree/search.html:306 templates/navbar.html:36 msgid "Manufacturers" msgstr "" -#: company/views.py:77 templates/InvenTree/search.html:336 +#: company/views.py:71 templates/InvenTree/search.html:336 #: templates/navbar.html:45 msgid "Customers" msgstr "" -#: company/views.py:78 order/templates/order/sales_orders.html:187 +#: company/views.py:72 msgid "New Customer" msgstr "" -#: company/views.py:86 +#: company/views.py:79 msgid "Companies" msgstr "" -#: company/views.py:87 +#: company/views.py:80 msgid "New Company" msgstr "" -#: company/views.py:169 part/views.py:937 +#: company/views.py:161 part/views.py:1007 msgid "Download Image" msgstr "" -#: company/views.py:198 part/views.py:969 +#: company/views.py:190 part/views.py:1039 msgid "Image size exceeds maximum allowable size for download" msgstr "" -#: company/views.py:205 part/views.py:976 +#: company/views.py:197 part/views.py:1046 #, python-brace-format msgid "Invalid response: {code}" msgstr "" -#: company/views.py:214 part/views.py:985 +#: company/views.py:206 part/views.py:1055 msgid "Supplied URL is not a valid image file" msgstr "" -#: company/views.py:243 -msgid "Update Company Image" -msgstr "" - -#: company/views.py:249 -msgid "Updated company image" -msgstr "" - -#: company/views.py:259 -msgid "Edit Company" -msgstr "" - -#: company/views.py:264 -msgid "Edited company information" -msgstr "" - -#: company/views.py:287 order/templates/order/sales_orders.html:188 -msgid "Create new Customer" -msgstr "" - -#: company/views.py:289 -msgid "Create new Company" -msgstr "" - -#: company/views.py:316 -msgid "Created new company" -msgstr "" - -#: company/views.py:332 -msgid "Company was deleted" -msgstr "" - -#: company/views.py:357 -msgid "Edit Manufacturer Part" -msgstr "" - -#: company/views.py:366 +#: company/views.py:251 msgid "Create New Manufacturer Part" msgstr "" -#: company/views.py:440 -msgid "Delete Manufacturer Part" -msgstr "" - -#: company/views.py:528 +#: company/views.py:334 msgid "Edit Supplier Part" msgstr "" -#: company/views.py:578 templates/js/stock.js:1294 +#: company/views.py:385 templates/js/stock.js:1333 msgid "Create new Supplier Part" msgstr "" -#: company/views.py:722 +#: company/views.py:529 msgid "Delete Supplier Part" msgstr "" -#: company/views.py:799 part/views.py:2737 -msgid "Added new price break" -msgstr "" - -#: company/views.py:855 part/views.py:2781 -msgid "Edit Price Break" -msgstr "" - -#: company/views.py:870 part/views.py:2795 -msgid "Delete Price Break" -msgstr "" - #: label/api.py:56 report/api.py:201 msgid "No valid objects provided to template" msgstr "" -#: label/models.py:103 +#: label/models.py:104 msgid "Label name" msgstr "" -#: label/models.py:110 +#: label/models.py:111 msgid "Label description" msgstr "" -#: label/models.py:117 stock/forms.py:202 +#: label/models.py:118 stock/forms.py:169 msgid "Label" msgstr "" -#: label/models.py:118 +#: label/models.py:119 msgid "Label template file" msgstr "" -#: label/models.py:124 report/models.py:274 +#: label/models.py:125 report/models.py:297 msgid "Enabled" msgstr "" -#: label/models.py:125 +#: label/models.py:126 msgid "Label template is enabled" msgstr "" -#: label/models.py:130 +#: label/models.py:131 msgid "Width [mm]" msgstr "" -#: label/models.py:131 +#: label/models.py:132 msgid "Label width, specified in mm" msgstr "" -#: label/models.py:137 +#: label/models.py:138 msgid "Height [mm]" msgstr "" -#: label/models.py:138 +#: label/models.py:139 msgid "Label height, specified in mm" msgstr "" -#: label/models.py:144 +#: label/models.py:145 report/models.py:290 msgid "Filename Pattern" msgstr "" -#: label/models.py:145 +#: label/models.py:146 msgid "Pattern for generating label filenames" msgstr "" -#: label/models.py:244 label/models.py:297 +#: label/models.py:249 label/models.py:306 msgid "Query filters (comma-separated list of key=value pairs" msgstr "" -#: label/models.py:245 label/models.py:298 report/models.py:294 -#: report/models.py:415 report/models.py:449 +#: label/models.py:250 label/models.py:307 report/models.py:317 +#: report/models.py:440 report/models.py:474 msgid "Filters" msgstr "" -#: order/forms.py:27 order/templates/order/order_base.html:47 +#: order/forms.py:30 order/templates/order/order_base.html:47 msgid "Place order" msgstr "" -#: order/forms.py:38 order/templates/order/order_base.html:54 +#: order/forms.py:41 order/templates/order/order_base.html:54 msgid "Mark order as complete" msgstr "" -#: order/forms.py:49 order/forms.py:60 order/templates/order/order_base.html:59 +#: order/forms.py:52 order/forms.py:63 order/templates/order/order_base.html:59 #: order/templates/order/sales_order_base.html:61 msgid "Cancel order" msgstr "" -#: order/forms.py:71 order/templates/order/sales_order_base.html:58 +#: order/forms.py:74 order/templates/order/sales_order_base.html:58 msgid "Ship order" msgstr "" -#: order/forms.py:82 +#: order/forms.py:89 msgid "Receive parts to this location" msgstr "" -#: order/forms.py:103 -msgid "Purchase Order reference" -msgstr "" - -#: order/forms.py:110 -msgid "Target date for order delivery. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:138 -msgid "Enter sales order number" -msgstr "" - -#: order/forms.py:145 order/models.py:475 -msgid "Target date for order completion. Order will be overdue after this date." -msgstr "" - -#: order/forms.py:236 +#: order/forms.py:116 msgid "Enter stock item serial numbers" msgstr "" -#: order/forms.py:242 +#: order/forms.py:122 msgid "Enter quantity of stock items" msgstr "" -#: order/models.py:101 -msgid "Order reference" -msgstr "" - -#: order/models.py:103 +#: order/models.py:154 msgid "Order description" msgstr "" -#: order/models.py:105 +#: order/models.py:156 msgid "Link to external page" msgstr "" -#: order/models.py:113 part/templates/part/detail.html:132 +#: order/models.py:164 part/templates/part/detail.html:132 msgid "Created By" msgstr "" -#: order/models.py:120 +#: order/models.py:171 msgid "User or group responsible for this order" msgstr "" -#: order/models.py:125 +#: order/models.py:176 msgid "Order notes" msgstr "" -#: order/models.py:184 order/models.py:468 +#: order/models.py:243 order/models.py:530 +msgid "Order reference" +msgstr "" + +#: order/models.py:248 order/models.py:545 msgid "Purchase order status" msgstr "" -#: order/models.py:193 +#: order/models.py:257 msgid "Company from which the items are being ordered" msgstr "" -#: order/models.py:196 order/templates/order/order_base.html:98 -#: templates/js/order.js:179 +#: order/models.py:260 order/templates/order/order_base.html:98 +#: templates/js/order.js:241 msgid "Supplier Reference" msgstr "" -#: order/models.py:196 +#: order/models.py:260 msgid "Supplier order reference code" msgstr "" -#: order/models.py:203 +#: order/models.py:267 msgid "received by" msgstr "" -#: order/models.py:208 +#: order/models.py:272 msgid "Issue Date" msgstr "" -#: order/models.py:209 +#: order/models.py:273 msgid "Date order was issued" msgstr "" -#: order/models.py:214 +#: order/models.py:278 msgid "Target Delivery Date" msgstr "" -#: order/models.py:215 +#: order/models.py:279 msgid "Expected date for order delivery. Order will be overdue after this date." msgstr "" -#: order/models.py:221 +#: order/models.py:285 msgid "Date order was completed" msgstr "" -#: order/models.py:245 part/views.py:1675 stock/models.py:304 -#: stock/models.py:1020 +#: order/models.py:309 part/views.py:1730 stock/models.py:308 +#: stock/models.py:1023 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:250 +#: order/models.py:314 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:348 +#: order/models.py:412 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:352 +#: order/models.py:416 msgid "Quantity must be an integer" msgstr "" -#: order/models.py:354 +#: order/models.py:418 msgid "Quantity must be a positive number" msgstr "" -#: order/models.py:464 +#: order/models.py:541 msgid "Company to which the items are being sold" msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer Reference " msgstr "" -#: order/models.py:470 +#: order/models.py:547 msgid "Customer order reference code" msgstr "" -#: order/models.py:478 templates/js/order.js:303 +#: order/models.py:552 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:555 templates/js/order.js:370 msgid "Shipment Date" msgstr "" -#: order/models.py:485 +#: order/models.py:562 msgid "shipped by" msgstr "" -#: order/models.py:529 +#: order/models.py:606 msgid "SalesOrder cannot be shipped as it is not currently pending" msgstr "" -#: order/models.py:616 +#: order/models.py:703 msgid "Item quantity" msgstr "" -#: order/models.py:618 +#: order/models.py:709 msgid "Line item reference" msgstr "" -#: order/models.py:620 +#: order/models.py:711 msgid "Line item notes" msgstr "" -#: order/models.py:646 order/models.py:691 -#: part/templates/part/allocation.html:17 -#: part/templates/part/allocation.html:45 +#: order/models.py:741 order/models.py:812 templates/js/order.js:420 msgid "Order" msgstr "" -#: order/models.py:647 order/templates/order/order_base.html:9 +#: order/models.py:742 order/templates/order/order_base.html:9 #: order/templates/order/order_base.html:24 #: report/templates/report/inventree_po_report.html:77 -#: stock/templates/stock/item_base.html:324 templates/js/order.js:148 -#: templates/js/stock.js:1053 +#: stock/templates/stock/item_base.html:324 templates/js/order.js:210 +#: templates/js/stock.js:669 templates/js/stock.js:1092 msgid "Purchase Order" msgstr "" -#: order/models.py:661 +#: order/models.py:756 msgid "Supplier part" msgstr "" -#: order/models.py:664 order/templates/order/order_base.html:131 -#: order/templates/order/purchase_order_detail.html:219 +#: order/models.py:759 order/templates/order/order_base.html:131 +#: order/templates/order/purchase_order_detail.html:246 #: order/templates/order/receive_parts.html:22 #: order/templates/order/sales_order_base.html:133 msgid "Received" msgstr "" -#: order/models.py:664 +#: order/models.py:759 msgid "Number of items received" msgstr "" -#: order/models.py:671 stock/models.py:542 -#: stock/templates/stock/item_base.html:331 templates/js/stock.js:665 +#: order/models.py:765 part/templates/part/prices.html:166 stock/models.py:545 +#: stock/templates/stock/item_base.html:331 templates/js/stock.js:704 msgid "Purchase Price" msgstr "" -#: order/models.py:672 +#: order/models.py:766 msgid "Unit purchase price" msgstr "" -#: order/models.py:700 part/templates/part/navbar.html:101 -#: part/templates/part/order_prices.html:82 -#: part/templates/part/part_pricing.html:78 +#: order/models.py:774 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:820 part/templates/part/part_pricing.html:97 +#: part/templates/part/prices.html:103 part/templates/part/prices.html:278 msgid "Sale Price" msgstr "" -#: order/models.py:701 +#: order/models.py:821 msgid "Unit sale price" msgstr "" -#: order/models.py:776 order/models.py:778 +#: order/models.py:900 order/models.py:902 msgid "Stock item has not been assigned" msgstr "" -#: order/models.py:782 +#: order/models.py:906 msgid "Cannot allocate stock item to a line with a different part" msgstr "" -#: order/models.py:784 +#: order/models.py:908 msgid "Cannot allocate stock to a line without a part" msgstr "" -#: order/models.py:787 +#: order/models.py:911 msgid "Allocation quantity cannot exceed stock quantity" msgstr "" -#: order/models.py:797 +#: order/models.py:921 msgid "Quantity must be 1 for serialized stock item" msgstr "" -#: order/models.py:802 +#: order/models.py:926 msgid "Line" msgstr "" -#: order/models.py:813 +#: order/models.py:937 msgid "Item" msgstr "" -#: order/models.py:814 +#: order/models.py:938 msgid "Select stock item to allocate" msgstr "" -#: order/models.py:817 +#: order/models.py:941 msgid "Enter stock allocation quantity" msgstr "" +#: order/serializers.py:139 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:359 +msgid "Sale price currency" +msgstr "" + #: order/templates/order/delete_attachment.html:5 #: stock/templates/stock/attachment_delete.html:5 #: templates/attachment_delete.html:5 @@ -2955,7 +3041,7 @@ msgid "Export order to file" msgstr "" #: order/templates/order/order_base.html:72 -#: order/templates/order/po_navbar.html:11 +#: order/templates/order/po_navbar.html:12 msgid "Purchase Order Details" msgstr "" @@ -2974,16 +3060,22 @@ msgstr "" msgid "Issued" msgstr "" -#: order/templates/order/order_base.html:180 -#: order/templates/order/purchase_order_detail.html:100 -#: part/templates/part/category.html:208 part/templates/part/category.html:250 -#: stock/templates/stock/location.html:191 templates/js/stock.js:711 -#: templates/js/stock.js:1299 +#: order/templates/order/order_base.html:188 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_base.html:199 +#: order/templates/order/purchase_order_detail.html:127 +#: part/templates/part/category.html:217 part/templates/part/category.html:259 +#: part/templates/part/part_base.html:415 +#: stock/templates/stock/location.html:191 templates/js/stock.js:750 +#: templates/js/stock.js:1338 msgid "New Location" msgstr "" -#: order/templates/order/order_base.html:181 -#: order/templates/order/purchase_order_detail.html:101 +#: order/templates/order/order_base.html:200 +#: order/templates/order/purchase_order_detail.html:128 +#: part/templates/part/part_base.html:416 #: stock/templates/stock/location.html:42 msgid "Create new stock location" msgstr "" @@ -3014,57 +3106,71 @@ msgstr "" #: order/templates/order/order_wizard/match_fields.html:9 #: part/templates/part/bom_upload/select_fields.html:21 +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: part/templates/part/import_wizard/match_fields.html:9 msgid "Missing selections for the following required columns" msgstr "" #: order/templates/order/order_wizard/match_fields.html:20 +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: part/templates/part/import_wizard/match_fields.html:20 msgid "Duplicate selections found, see below. Fix them then retry submitting." msgstr "" -#: order/templates/order/order_wizard/match_fields.html:27 -#: order/templates/order/order_wizard/match_parts.html:18 -#: order/templates/order/order_wizard/po_upload.html:40 -msgid "Previous Step" -msgstr "" - #: order/templates/order/order_wizard/match_fields.html:29 -#: order/templates/order/order_wizard/match_parts.html:20 +#: order/templates/order/order_wizard/match_parts.html:21 #: part/templates/part/bom_upload/select_fields.html:32 +#: part/templates/part/import_wizard/match_fields.html:29 +#: part/templates/part/import_wizard/match_references.html:21 msgid "Submit Selections" msgstr "" #: order/templates/order/order_wizard/match_fields.html:35 #: part/templates/part/bom_upload/select_fields.html:41 +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: part/templates/part/import_wizard/match_fields.html:35 msgid "File Fields" msgstr "" #: order/templates/order/order_wizard/match_fields.html:42 #: part/templates/part/bom_upload/select_fields.html:47 +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: part/templates/part/import_wizard/match_fields.html:42 msgid "Remove column" msgstr "" #: order/templates/order/order_wizard/match_fields.html:60 +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: part/templates/part/import_wizard/match_fields.html:60 msgid "Duplicate selection" msgstr "" #: order/templates/order/order_wizard/match_fields.html:71 -#: order/templates/order/order_wizard/match_parts.html:51 +#: order/templates/order/order_wizard/match_parts.html:52 #: part/templates/part/bom_upload/select_fields.html:76 #: part/templates/part/bom_upload/select_parts.html:58 +#: part/templates/part/import_wizard/ajax_match_fields.html:64 +#: part/templates/part/import_wizard/ajax_match_references.html:42 +#: part/templates/part/import_wizard/match_fields.html:71 +#: part/templates/part/import_wizard/match_references.html:49 msgid "Remove row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:11 +#: order/templates/order/order_wizard/match_parts.html:12 #: part/templates/part/bom_upload/select_parts.html:21 +#: part/templates/part/import_wizard/ajax_match_references.html:12 +#: part/templates/part/import_wizard/match_references.html:12 msgid "Errors exist in the submitted data" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:27 +#: order/templates/order/order_wizard/match_parts.html:28 #: part/templates/part/bom_upload/select_parts.html:39 +#: part/templates/part/import_wizard/ajax_match_references.html:21 +#: part/templates/part/import_wizard/match_references.html:28 msgid "Row" msgstr "" -#: order/templates/order/order_wizard/match_parts.html:28 +#: order/templates/order/order_wizard/match_parts.html:29 msgid "Select Supplier Part" msgstr "" @@ -3073,6 +3179,8 @@ msgid "Upload File for Purchase Order" msgstr "" #: order/templates/order/order_wizard/po_upload.html:18 +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: part/templates/part/import_wizard/part_upload.html:21 #, python-format msgid "Step %(step)s of %(count)s" msgstr "" @@ -3081,28 +3189,32 @@ msgstr "" msgid "Order is already processed. Files cannot be uploaded." msgstr "" -#: order/templates/order/order_wizard/select_parts.html:9 +#: order/templates/order/order_wizard/select_parts.html:11 msgid "Step 1 of 2 - Select Part Suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:14 +#: order/templates/order/order_wizard/select_parts.html:16 msgid "Select suppliers" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:18 +#: order/templates/order/order_wizard/select_parts.html:20 msgid "No purchaseable parts selected" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:31 +#: order/templates/order/order_wizard/select_parts.html:33 msgid "Select Supplier" msgstr "" #: order/templates/order/order_wizard/select_parts.html:57 +msgid "No price" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:65 #, python-format msgid "Select a supplier for %(name)s" msgstr "" -#: order/templates/order/order_wizard/select_parts.html:69 +#: order/templates/order/order_wizard/select_parts.html:77 #: part/templates/part/set_category.html:32 msgid "Remove part" msgstr "" @@ -3116,7 +3228,7 @@ msgid "Select existing purchase orders, or create new orders." msgstr "" #: order/templates/order/order_wizard/select_pos.html:31 -#: templates/js/order.js:205 templates/js/order.js:308 +#: templates/js/order.js:267 templates/js/order.js:375 msgid "Items" msgstr "" @@ -3135,15 +3247,19 @@ msgid "Select a purchase order for %(name)s" msgstr "" #: order/templates/order/po_attachments.html:12 -#: order/templates/order/po_navbar.html:23 +#: order/templates/order/po_navbar.html:32 msgid "Purchase Order Attachments" msgstr "" -#: order/templates/order/po_navbar.html:17 +#: order/templates/order/po_lineitem_delete.html:5 +msgid "Are you sure you wish to delete this line item?" +msgstr "" + +#: order/templates/order/po_navbar.html:26 msgid "Received Stock Items" msgstr "" -#: order/templates/order/po_navbar.html:20 +#: order/templates/order/po_navbar.html:29 #: order/templates/order/po_received_items.html:12 msgid "Received Items" msgstr "" @@ -3153,34 +3269,52 @@ msgid "Purchase Order Items" msgstr "" #: order/templates/order/purchase_order_detail.html:24 -#: order/templates/order/sales_order_detail.html:22 order/views.py:1311 -#: order/views.py:1394 +#: order/templates/order/purchase_order_detail.html:64 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:56 msgid "Add Line Item" msgstr "" -#: order/templates/order/purchase_order_detail.html:114 +#: order/templates/order/purchase_order_detail.html:100 +#: order/templates/order/sales_order_detail.html:398 +msgid "Edit Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/sales_order_detail.html:408 +msgid "Delete Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:141 msgid "No line items found" msgstr "" -#: order/templates/order/purchase_order_detail.html:191 -#: order/templates/order/sales_order_detail.html:235 +#: order/templates/order/purchase_order_detail.html:169 +#: order/templates/order/sales_order_detail.html:233 +msgid "Total" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:218 +#: order/templates/order/sales_order_detail.html:256 templates/js/part.js:807 +#: templates/js/part.js:996 msgid "Unit Price" msgstr "" -#: order/templates/order/purchase_order_detail.html:198 +#: order/templates/order/purchase_order_detail.html:225 +#: order/templates/order/sales_order_detail.html:263 msgid "Total price" msgstr "" -#: order/templates/order/purchase_order_detail.html:251 -#: order/templates/order/sales_order_detail.html:328 +#: order/templates/order/purchase_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:369 msgid "Edit line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:252 +#: order/templates/order/purchase_order_detail.html:283 msgid "Delete line item" msgstr "" -#: order/templates/order/purchase_order_detail.html:257 +#: order/templates/order/purchase_order_detail.html:288 msgid "Receive line item" msgstr "" @@ -3195,15 +3329,15 @@ msgid "Receive outstanding parts for %(order)s - %(desc)s" msgstr "" #: order/templates/order/receive_parts.html:14 part/api.py:45 -#: part/models.py:322 part/templates/part/cat_link.html:7 -#: part/templates/part/category.html:99 part/templates/part/category.html:148 -#: part/templates/part/category_navbar.html:22 -#: part/templates/part/category_navbar.html:29 +#: part/models.py:326 part/templates/part/cat_link.html:7 +#: part/templates/part/category.html:108 part/templates/part/category.html:157 +#: part/templates/part/category_navbar.html:25 +#: part/templates/part/category_navbar.html:32 #: part/templates/part/category_partlist.html:10 #: templates/InvenTree/index.html:97 templates/InvenTree/search.html:114 -#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:665 +#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:666 #: templates/navbar.html:23 templates/stats.html:80 templates/stats.html:89 -#: users/models.py:40 +#: users/models.py:41 msgid "Parts" msgstr "" @@ -3216,7 +3350,7 @@ msgid "Order Code" msgstr "" #: order/templates/order/receive_parts.html:21 -#: part/templates/part/part_base.html:136 templates/js/part.js:480 +#: part/templates/part/part_base.html:136 templates/js/part.js:481 msgid "On Order" msgstr "" @@ -3224,11 +3358,11 @@ msgstr "" msgid "Receive" msgstr "" -#: order/templates/order/receive_parts.html:36 +#: order/templates/order/receive_parts.html:37 msgid "Error: Referenced part has been removed" msgstr "" -#: order/templates/order/receive_parts.html:57 +#: order/templates/order/receive_parts.html:61 msgid "Remove line" msgstr "" @@ -3245,10 +3379,14 @@ msgstr "" msgid "Sales Order Details" msgstr "" -#: order/templates/order/sales_order_base.html:100 templates/js/order.js:275 +#: order/templates/order/sales_order_base.html:100 templates/js/order.js:342 msgid "Customer Reference" msgstr "" +#: order/templates/order/sales_order_base.html:177 +msgid "Edit Sales Order" +msgstr "" + #: order/templates/order/sales_order_cancel.html:8 #: order/templates/order/sales_order_ship.html:9 #: part/templates/part/bom_duplicate.html:12 @@ -3264,69 +3402,69 @@ msgstr "" msgid "Sales Order Items" msgstr "" -#: order/templates/order/sales_order_detail.html:95 templates/js/bom.js:365 -#: templates/js/build.js:637 templates/js/build.js:1054 +#: order/templates/order/sales_order_detail.html:105 templates/js/bom.js:358 +#: templates/js/build.js:725 templates/js/build.js:1142 msgid "Actions" msgstr "" -#: order/templates/order/sales_order_detail.html:102 templates/js/build.js:525 -#: templates/js/build.js:859 +#: order/templates/order/sales_order_detail.html:112 templates/js/build.js:611 +#: templates/js/build.js:947 msgid "Edit stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:103 templates/js/build.js:527 -#: templates/js/build.js:860 +#: order/templates/order/sales_order_detail.html:113 templates/js/build.js:613 +#: templates/js/build.js:948 msgid "Delete stock allocation" msgstr "" -#: order/templates/order/sales_order_detail.html:176 +#: order/templates/order/sales_order_detail.html:186 msgid "No matching line items" msgstr "" -#: order/templates/order/sales_order_detail.html:205 +#: order/templates/order/sales_order_detail.html:216 msgid "ID" msgstr "" -#: order/templates/order/sales_order_detail.html:243 templates/js/build.js:589 -#: templates/js/build.js:855 +#: order/templates/order/sales_order_detail.html:284 templates/js/build.js:676 +#: templates/js/build.js:943 msgid "Allocated" msgstr "" -#: order/templates/order/sales_order_detail.html:245 +#: order/templates/order/sales_order_detail.html:286 msgid "Fulfilled" msgstr "" -#: order/templates/order/sales_order_detail.html:282 +#: order/templates/order/sales_order_detail.html:323 msgid "PO" msgstr "" -#: order/templates/order/sales_order_detail.html:312 +#: order/templates/order/sales_order_detail.html:353 msgid "Allocate serial numbers" msgstr "" -#: order/templates/order/sales_order_detail.html:315 templates/js/build.js:651 +#: order/templates/order/sales_order_detail.html:356 templates/js/build.js:739 msgid "Allocate stock" msgstr "" -#: order/templates/order/sales_order_detail.html:318 +#: order/templates/order/sales_order_detail.html:359 msgid "Purchase stock" msgstr "" -#: order/templates/order/sales_order_detail.html:322 templates/js/build.js:644 -#: templates/js/build.js:1062 +#: order/templates/order/sales_order_detail.html:363 templates/js/build.js:732 +#: templates/js/build.js:1150 msgid "Build stock" msgstr "" -#: order/templates/order/sales_order_detail.html:325 -#: order/templates/order/sales_order_detail.html:434 +#: order/templates/order/sales_order_detail.html:366 +#: order/templates/order/sales_order_detail.html:485 msgid "Calculate price" msgstr "" -#: order/templates/order/sales_order_detail.html:329 +#: order/templates/order/sales_order_detail.html:370 msgid "Delete line item " msgstr "" -#: order/templates/order/sales_order_detail.html:440 +#: order/templates/order/sales_order_detail.html:491 msgid "Update Unit Price" msgstr "" @@ -3367,195 +3505,155 @@ msgstr "" msgid "Sales Order Attachments" msgstr "" -#: order/templates/order/so_lineitem_delete.html:5 -msgid "Are you sure you wish to delete this line item?" -msgstr "" - -#: order/views.py:104 -msgid "Add Purchase Order Attachment" -msgstr "" - -#: order/views.py:154 -msgid "Add Sales Order Attachment" -msgstr "" - -#: order/views.py:346 -msgid "Create Sales Order" -msgstr "" - -#: order/views.py:381 -msgid "Edit Purchase Order" -msgstr "" - -#: order/views.py:401 -msgid "Edit Sales Order" -msgstr "" - -#: order/views.py:417 +#: order/views.py:151 msgid "Cancel Order" msgstr "" -#: order/views.py:426 order/views.py:452 +#: order/views.py:160 order/views.py:186 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:429 order/views.py:455 +#: order/views.py:163 order/views.py:189 msgid "Order cannot be cancelled" msgstr "" -#: order/views.py:443 +#: order/views.py:177 msgid "Cancel sales order" msgstr "" -#: order/views.py:469 +#: order/views.py:203 msgid "Issue Order" msgstr "" -#: order/views.py:478 +#: order/views.py:212 msgid "Confirm order placement" msgstr "" -#: order/views.py:488 +#: order/views.py:222 msgid "Purchase order issued" msgstr "" -#: order/views.py:499 +#: order/views.py:233 msgid "Complete Order" msgstr "" -#: order/views.py:515 +#: order/views.py:249 msgid "Confirm order completion" msgstr "" -#: order/views.py:526 +#: order/views.py:260 msgid "Purchase order completed" msgstr "" -#: order/views.py:536 +#: order/views.py:270 msgid "Ship Order" msgstr "" -#: order/views.py:552 +#: order/views.py:286 msgid "Confirm order shipment" msgstr "" -#: order/views.py:558 +#: order/views.py:292 msgid "Could not ship order" msgstr "" -#: order/views.py:584 +#: order/views.py:339 msgid "Match Supplier Parts" msgstr "" -#: order/views.py:798 +#: order/views.py:536 msgid "Receive Parts" msgstr "" -#: order/views.py:868 +#: order/views.py:606 msgid "Items received" msgstr "" -#: order/views.py:882 +#: order/views.py:620 msgid "No destination set" msgstr "" -#: order/views.py:927 +#: order/views.py:665 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:933 +#: order/views.py:671 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:939 +#: order/views.py:677 msgid "No lines specified" msgstr "" -#: order/views.py:1260 +#: order/views.py:750 +msgid "Update prices" +msgstr "" + +#: order/views.py:1008 #, python-brace-format msgid "Ordered {n} parts" msgstr "" -#: order/views.py:1320 -msgid "Supplier part must be specified" -msgstr "" - -#: order/views.py:1326 -msgid "Supplier must match for Part and Order" -msgstr "" - -#: order/views.py:1457 order/views.py:1475 -msgid "Edit Line Item" -msgstr "" - -#: order/views.py:1491 order/views.py:1503 -msgid "Delete Line Item" -msgstr "" - -#: order/views.py:1496 order/views.py:1508 -msgid "Deleted line item" -msgstr "" - -#: order/views.py:1521 +#: order/views.py:1061 msgid "Allocate Serial Numbers" msgstr "" -#: order/views.py:1566 +#: order/views.py:1106 #, python-brace-format msgid "Allocated {n} items" msgstr "" -#: order/views.py:1582 +#: order/views.py:1122 msgid "Select line item" msgstr "" -#: order/views.py:1613 +#: order/views.py:1153 #, python-brace-format msgid "No matching item for serial {serial}" msgstr "" -#: order/views.py:1623 +#: order/views.py:1163 #, python-brace-format msgid "{serial} is not in stock" msgstr "" -#: order/views.py:1631 +#: order/views.py:1171 #, python-brace-format msgid "{serial} already allocated to an order" msgstr "" -#: order/views.py:1685 +#: order/views.py:1225 msgid "Allocate Stock to Order" msgstr "" -#: order/views.py:1759 +#: order/views.py:1299 msgid "Edit Allocation Quantity" msgstr "" -#: order/views.py:1774 +#: order/views.py:1314 msgid "Remove allocation" msgstr "" -#: order/views.py:1846 +#: order/views.py:1386 msgid "Sales order not found" msgstr "" -#: order/views.py:1852 +#: order/views.py:1392 msgid "Price not found" msgstr "" -#: order/views.py:1855 +#: order/views.py:1395 #, python-brace-format msgid "Updated {part} unit-price to {price}" msgstr "" -#: order/views.py:1860 +#: order/views.py:1400 #, python-brace-format msgid "Updated {part} unit-price to {price} and quantity to {qty}" msgstr "" -#: part/bom.py:138 part/models.py:72 part/models.py:762 -#: part/templates/part/category.html:66 part/templates/part/detail.html:90 +#: part/bom.py:138 part/models.py:72 part/models.py:756 +#: part/templates/part/category.html:75 part/templates/part/detail.html:90 msgid "Default Location" msgstr "" @@ -3576,143 +3674,143 @@ msgstr "" msgid "Error reading BOM file (incorrect row size)" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "File Format" msgstr "" -#: part/forms.py:89 stock/forms.py:265 +#: part/forms.py:73 stock/forms.py:232 msgid "Select output file format" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Cascading" msgstr "" -#: part/forms.py:91 +#: part/forms.py:75 msgid "Download cascading / multi-level BOM" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Levels" msgstr "" -#: part/forms.py:93 +#: part/forms.py:77 msgid "Select maximum number of BOM levels to export (0 = all levels)" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include Parameter Data" msgstr "" -#: part/forms.py:95 +#: part/forms.py:79 msgid "Include part parameters data in exported BOM" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include Stock Data" msgstr "" -#: part/forms.py:97 +#: part/forms.py:81 msgid "Include part stock data in exported BOM" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include Manufacturer Data" msgstr "" -#: part/forms.py:99 +#: part/forms.py:83 msgid "Include part manufacturer data in exported BOM" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include Supplier Data" msgstr "" -#: part/forms.py:101 +#: part/forms.py:85 msgid "Include part supplier data in exported BOM" msgstr "" -#: part/forms.py:122 part/models.py:2168 +#: part/forms.py:106 part/models.py:2224 msgid "Parent Part" msgstr "" -#: part/forms.py:123 part/templates/part/bom_duplicate.html:7 +#: part/forms.py:107 part/templates/part/bom_duplicate.html:7 msgid "Select parent part to copy BOM from" msgstr "" -#: part/forms.py:129 +#: part/forms.py:113 msgid "Clear existing BOM items" msgstr "" -#: part/forms.py:135 +#: part/forms.py:119 msgid "Confirm BOM duplication" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "validate" msgstr "" -#: part/forms.py:153 +#: part/forms.py:137 msgid "Confirm that the BOM is correct" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "BOM file" msgstr "" -#: part/forms.py:165 +#: part/forms.py:149 msgid "Select BOM file to upload" msgstr "" -#: part/forms.py:184 +#: part/forms.py:168 msgid "Related Part" msgstr "" -#: part/forms.py:203 +#: part/forms.py:175 msgid "Select part category" msgstr "" -#: part/forms.py:220 +#: part/forms.py:192 msgid "Duplicate all BOM data for this part" msgstr "" -#: part/forms.py:221 +#: part/forms.py:193 msgid "Copy BOM" msgstr "" -#: part/forms.py:226 +#: part/forms.py:198 msgid "Duplicate all parameter data for this part" msgstr "" -#: part/forms.py:227 +#: part/forms.py:199 msgid "Copy Parameters" msgstr "" -#: part/forms.py:232 +#: part/forms.py:204 msgid "Confirm part creation" msgstr "" -#: part/forms.py:237 +#: part/forms.py:209 msgid "Include category parameter templates" msgstr "" -#: part/forms.py:242 +#: part/forms.py:214 msgid "Include parent categories parameter templates" msgstr "" -#: part/forms.py:322 +#: part/forms.py:294 msgid "Add parameter template to same level categories" msgstr "" -#: part/forms.py:326 +#: part/forms.py:298 msgid "Add parameter template to all categories" msgstr "" -#: part/forms.py:344 part/models.py:2263 +#: part/forms.py:316 part/models.py:2323 msgid "Sub part" msgstr "" -#: part/forms.py:373 +#: part/forms.py:345 msgid "Input quantity for price calculation" msgstr "" @@ -3728,392 +3826,379 @@ msgstr "" msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:82 part/models.py:2214 +#: part/models.py:86 part/models.py:2270 #: part/templates/part/part_app_base.html:10 msgid "Part Category" msgstr "" -#: part/models.py:83 part/templates/part/category.html:23 -#: part/templates/part/category.html:94 templates/InvenTree/search.html:127 -#: templates/stats.html:84 users/models.py:39 +#: part/models.py:87 part/templates/part/category.html:32 +#: part/templates/part/category.html:103 templates/InvenTree/search.html:127 +#: templates/stats.html:84 users/models.py:40 msgid "Part Categories" msgstr "" -#: part/models.py:446 part/models.py:458 +#: part/models.py:457 part/models.py:469 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" -#: part/models.py:555 +#: part/models.py:566 msgid "Next available serial numbers are" msgstr "" -#: part/models.py:559 +#: part/models.py:570 msgid "Next available serial number is" msgstr "" -#: part/models.py:564 +#: part/models.py:575 msgid "Most recent serial number is" msgstr "" -#: part/models.py:643 +#: part/models.py:654 msgid "Duplicate IPN not allowed in part settings" msgstr "" -#: part/models.py:654 -msgid "Part must be unique for name, IPN and revision" -msgstr "" - -#: part/models.py:685 part/templates/part/detail.html:22 +#: part/models.py:679 part/templates/part/detail.html:22 msgid "Part name" msgstr "" -#: part/models.py:692 +#: part/models.py:686 msgid "Is Template" msgstr "" -#: part/models.py:693 +#: part/models.py:687 msgid "Is this part a template part?" msgstr "" -#: part/models.py:704 +#: part/models.py:698 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:705 part/templates/part/detail.html:60 +#: part/models.py:699 part/templates/part/detail.html:60 msgid "Variant Of" msgstr "" -#: part/models.py:711 +#: part/models.py:705 msgid "Part description" msgstr "" -#: part/models.py:716 part/templates/part/category.html:73 +#: part/models.py:710 part/templates/part/category.html:82 #: part/templates/part/detail.html:67 msgid "Keywords" msgstr "" -#: part/models.py:717 +#: part/models.py:711 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:724 part/models.py:2213 part/templates/part/detail.html:73 -#: part/templates/part/set_category.html:15 templates/js/part.js:451 +#: part/models.py:718 part/models.py:2269 part/templates/part/detail.html:73 +#: part/templates/part/set_category.html:15 templates/js/part.js:452 msgid "Category" msgstr "" -#: part/models.py:725 +#: part/models.py:719 msgid "Part category" msgstr "" -#: part/models.py:730 part/templates/part/detail.html:28 +#: part/models.py:724 part/templates/part/detail.html:28 #: part/templates/part/part_base.html:87 templates/js/part.js:169 #: templates/js/part.js:296 msgid "IPN" msgstr "" -#: part/models.py:731 +#: part/models.py:725 msgid "Internal Part Number" msgstr "" -#: part/models.py:737 +#: part/models.py:731 msgid "Part revision or version number" msgstr "" -#: part/models.py:738 part/templates/part/detail.html:35 report/models.py:198 +#: part/models.py:732 part/templates/part/detail.html:35 report/models.py:199 #: templates/js/part.js:173 msgid "Revision" msgstr "" -#: part/models.py:760 +#: part/models.py:754 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:807 part/templates/part/detail.html:97 +#: part/models.py:801 part/templates/part/detail.html:97 msgid "Default Supplier" msgstr "" -#: part/models.py:808 +#: part/models.py:802 msgid "Default supplier part" msgstr "" -#: part/models.py:815 +#: part/models.py:809 msgid "Default Expiry" msgstr "" -#: part/models.py:816 +#: part/models.py:810 msgid "Expiry time (in days) for stock items of this part" msgstr "" -#: part/models.py:821 part/templates/part/detail.html:113 +#: part/models.py:815 part/templates/part/detail.html:113 msgid "Minimum Stock" msgstr "" -#: part/models.py:822 +#: part/models.py:816 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:828 part/models.py:2142 part/templates/part/detail.html:106 -#: part/templates/part/params.html:29 -msgid "Units" -msgstr "" - -#: part/models.py:829 +#: part/models.py:823 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:835 +#: part/models.py:829 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:841 +#: part/models.py:835 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:847 +#: part/models.py:841 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:852 +#: part/models.py:846 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:857 +#: part/models.py:851 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:861 part/templates/part/detail.html:227 +#: part/models.py:855 part/templates/part/detail.html:227 #: templates/js/table_filters.js:21 templates/js/table_filters.js:65 -#: templates/js/table_filters.js:241 templates/js/table_filters.js:310 +#: templates/js/table_filters.js:246 templates/js/table_filters.js:315 msgid "Active" msgstr "" -#: part/models.py:862 +#: part/models.py:856 msgid "Is this part active?" msgstr "" -#: part/models.py:867 +#: part/models.py:861 msgid "Is this a virtual part, such as a software product or license?" msgstr "" -#: part/models.py:872 +#: part/models.py:866 msgid "Part notes - supports Markdown formatting" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "BOM checksum" msgstr "" -#: part/models.py:875 +#: part/models.py:869 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:878 +#: part/models.py:872 msgid "BOM checked by" msgstr "" -#: part/models.py:880 +#: part/models.py:874 msgid "BOM checked date" msgstr "" -#: part/models.py:884 +#: part/models.py:878 msgid "Creation User" msgstr "" -#: part/models.py:1616 +#: part/models.py:1617 msgid "Sell multiple" msgstr "" -#: part/models.py:2040 +#: part/models.py:2088 msgid "Test templates can only be created for trackable parts" msgstr "" -#: part/models.py:2057 +#: part/models.py:2105 msgid "Test with this name already exists for this part" msgstr "" -#: part/models.py:2077 templates/js/part.js:716 templates/js/stock.js:117 +#: part/models.py:2125 templates/js/part.js:717 templates/js/stock.js:117 msgid "Test Name" msgstr "" -#: part/models.py:2078 +#: part/models.py:2126 msgid "Enter a name for the test" msgstr "" -#: part/models.py:2083 +#: part/models.py:2131 msgid "Test Description" msgstr "" -#: part/models.py:2084 +#: part/models.py:2132 msgid "Enter description for this test" msgstr "" -#: part/models.py:2089 templates/js/part.js:725 -#: templates/js/table_filters.js:227 +#: part/models.py:2137 templates/js/part.js:726 +#: templates/js/table_filters.js:232 msgid "Required" msgstr "" -#: part/models.py:2090 +#: part/models.py:2138 msgid "Is this test required to pass?" msgstr "" -#: part/models.py:2095 templates/js/part.js:733 +#: part/models.py:2143 templates/js/part.js:734 msgid "Requires Value" msgstr "" -#: part/models.py:2096 +#: part/models.py:2144 msgid "Does this test require a value when adding a test result?" msgstr "" -#: part/models.py:2101 templates/js/part.js:740 +#: part/models.py:2149 templates/js/part.js:741 msgid "Requires Attachment" msgstr "" -#: part/models.py:2102 +#: part/models.py:2150 msgid "Does this test require a file attachment when adding a test result?" msgstr "" -#: part/models.py:2135 +#: part/models.py:2187 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:2140 +#: part/models.py:2192 msgid "Parameter Name" msgstr "" -#: part/models.py:2142 +#: part/models.py:2194 msgid "Parameter Units" msgstr "" -#: part/models.py:2170 part/models.py:2219 part/models.py:2220 +#: part/models.py:2226 part/models.py:2275 part/models.py:2276 #: templates/InvenTree/settings/category.html:62 msgid "Parameter Template" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Data" msgstr "" -#: part/models.py:2172 +#: part/models.py:2228 msgid "Parameter Value" msgstr "" -#: part/models.py:2224 templates/InvenTree/settings/category.html:67 +#: part/models.py:2280 templates/InvenTree/settings/category.html:67 msgid "Default Value" msgstr "" -#: part/models.py:2225 +#: part/models.py:2281 msgid "Default Parameter Value" msgstr "" -#: part/models.py:2255 +#: part/models.py:2315 msgid "Select parent part" msgstr "" -#: part/models.py:2264 +#: part/models.py:2324 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:2270 +#: part/models.py:2330 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:2272 templates/js/bom.js:216 templates/js/bom.js:285 +#: part/models.py:2332 templates/js/bom.js:216 templates/js/bom.js:278 msgid "Optional" msgstr "" -#: part/models.py:2272 +#: part/models.py:2332 msgid "This BOM item is optional" msgstr "" -#: part/models.py:2275 +#: part/models.py:2335 msgid "Overage" msgstr "" -#: part/models.py:2276 +#: part/models.py:2336 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:2279 +#: part/models.py:2339 msgid "BOM item reference" msgstr "" -#: part/models.py:2282 +#: part/models.py:2342 msgid "BOM item notes" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "Checksum" msgstr "" -#: part/models.py:2284 +#: part/models.py:2344 msgid "BOM line checksum" msgstr "" -#: part/models.py:2288 templates/js/bom.js:302 templates/js/bom.js:309 +#: part/models.py:2348 templates/js/bom.js:295 templates/js/bom.js:302 #: templates/js/table_filters.js:51 msgid "Inherited" msgstr "" -#: part/models.py:2289 +#: part/models.py:2349 msgid "This BOM item is inherited by BOMs for variant parts" msgstr "" -#: part/models.py:2294 templates/js/bom.js:294 +#: part/models.py:2354 templates/js/bom.js:287 msgid "Allow Variants" msgstr "" -#: part/models.py:2295 +#: part/models.py:2355 msgid "Stock items for variant parts can be used for this BOM item" msgstr "" -#: part/models.py:2371 part/views.py:1681 part/views.py:1733 -#: stock/models.py:294 +#: part/models.py:2431 part/views.py:1736 part/views.py:1788 +#: stock/models.py:298 msgid "Quantity must be integer value for trackable parts" msgstr "" -#: part/models.py:2380 part/models.py:2382 +#: part/models.py:2440 part/models.py:2442 msgid "Sub part must be specified" msgstr "" -#: part/models.py:2385 +#: part/models.py:2445 msgid "BOM Item" msgstr "" -#: part/models.py:2502 +#: part/models.py:2564 msgid "Part 1" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Part 2" msgstr "" -#: part/models.py:2506 +#: part/models.py:2568 msgid "Select Related Part" msgstr "" -#: part/models.py:2538 +#: part/models.py:2600 msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" msgstr "" #: part/templates/part/allocation.html:11 -msgid "Part Stock Allocations" +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/allocation.html:24 +msgid "Sales Order Allocations" msgstr "" #: part/templates/part/attachments.html:10 msgid "Part Attachments" msgstr "" -#: part/templates/part/bom-delete.html:6 -msgid "Are you sure you want to delete this BOM item?" -msgstr "" - -#: part/templates/part/bom-delete.html:8 -msgid "Deleting this entry will remove the BOM row from the following part" -msgstr "" - -#: part/templates/part/bom.html:10 part/templates/part/navbar.html:48 -#: part/templates/part/navbar.html:51 +#: part/templates/part/bom.html:10 part/templates/part/navbar.html:51 +#: part/templates/part/navbar.html:54 msgid "Bill of Materials" msgstr "" @@ -4160,7 +4245,7 @@ msgstr "" msgid "Validate Bill of Materials" msgstr "" -#: part/templates/part/bom.html:61 part/views.py:1976 +#: part/templates/part/bom.html:61 part/views.py:2031 msgid "Export Bill of Materials" msgstr "" @@ -4176,8 +4261,8 @@ msgstr "" msgid "All selected BOM items will be deleted" msgstr "" -#: part/templates/part/bom.html:160 part/views.py:585 -#: templates/js/stock.js:1288 +#: part/templates/part/bom.html:160 part/views.py:450 +#: templates/js/stock.js:1327 msgid "Create New Part" msgstr "" @@ -4213,7 +4298,7 @@ msgid "Select Part" msgstr "" #: part/templates/part/bom_upload/select_parts.html:65 -#: part/templates/part/category.html:117 +#: part/templates/part/category.html:126 msgid "Create new part" msgstr "" @@ -4254,90 +4339,99 @@ msgstr "" msgid "Start New Build" msgstr "" -#: part/templates/part/category.html:24 +#: part/templates/part/category.html:33 msgid "All parts" msgstr "" -#: part/templates/part/category.html:29 part/views.py:2379 +#: part/templates/part/category.html:38 part/views.py:2441 msgid "Create new part category" msgstr "" -#: part/templates/part/category.html:35 +#: part/templates/part/category.html:44 msgid "Edit part category" msgstr "" -#: part/templates/part/category.html:40 +#: part/templates/part/category.html:49 msgid "Delete part category" msgstr "" -#: part/templates/part/category.html:50 part/templates/part/category.html:89 +#: part/templates/part/category.html:59 part/templates/part/category.html:98 msgid "Category Details" msgstr "" -#: part/templates/part/category.html:55 +#: part/templates/part/category.html:64 msgid "Category Path" msgstr "" -#: part/templates/part/category.html:60 +#: part/templates/part/category.html:69 msgid "Category Description" msgstr "" -#: part/templates/part/category.html:79 -#: part/templates/part/category_navbar.html:11 -#: part/templates/part/category_navbar.html:18 +#: part/templates/part/category.html:88 +#: part/templates/part/category_navbar.html:14 +#: part/templates/part/category_navbar.html:21 #: part/templates/part/subcategory.html:16 msgid "Subcategories" msgstr "" -#: part/templates/part/category.html:84 +#: part/templates/part/category.html:93 msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:113 +#: part/templates/part/category.html:122 msgid "Export Part Data" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set category" msgstr "" -#: part/templates/part/category.html:125 +#: part/templates/part/category.html:134 msgid "Set Category" msgstr "" -#: part/templates/part/category.html:128 +#: part/templates/part/category.html:137 msgid "Export Data" msgstr "" -#: part/templates/part/category.html:132 +#: part/templates/part/category.html:141 msgid "View list display" msgstr "" -#: part/templates/part/category.html:135 +#: part/templates/part/category.html:144 msgid "View grid display" msgstr "" -#: part/templates/part/category.html:209 -#: stock/templates/stock/location.html:192 templates/js/stock.js:712 +#: part/templates/part/category.html:218 +#: stock/templates/stock/location.html:192 templates/js/stock.js:751 msgid "Create new location" msgstr "" -#: part/templates/part/category.html:214 part/templates/part/category.html:244 +#: part/templates/part/category.html:223 part/templates/part/category.html:253 +#: part/templates/part/part_base.html:378 msgid "New Category" msgstr "" -#: part/templates/part/category.html:215 +#: part/templates/part/category.html:224 msgid "Create new category" msgstr "" -#: part/templates/part/category.html:245 +#: part/templates/part/category.html:254 msgid "Create new Part Category" msgstr "" -#: part/templates/part/category.html:251 stock/views.py:1391 +#: part/templates/part/category.html:260 stock/views.py:1223 msgid "Create new Stock Location" msgstr "" +#: part/templates/part/category.html:279 +msgid "Select parent category" +msgstr "" + +#: part/templates/part/category.html:286 part/views.py:2389 +msgid "Edit Part Category" +msgstr "" + #: part/templates/part/category_delete.html:5 msgid "Are you sure you want to delete category" msgstr "" @@ -4373,18 +4467,17 @@ msgstr "" msgid "If this category is deleted, these parts will be moved to the top-level category Teile" msgstr "" -#: part/templates/part/category_navbar.html:34 #: part/templates/part/category_navbar.html:37 -#: part/templates/part/navbar.html:22 -msgid "Parameters" +#: part/templates/part/category_navbar.html:40 +msgid "Import Parts" msgstr "" #: part/templates/part/category_parametric.html:10 -#: part/templates/part/navbar.html:19 part/templates/part/params.html:10 +#: part/templates/part/navbar.html:22 part/templates/part/params.html:10 msgid "Part Parameters" msgstr "" -#: part/templates/part/copy_part.html:9 part/views.py:461 +#: part/templates/part/copy_part.html:9 part/views.py:326 msgid "Duplicate Part" msgstr "" @@ -4408,7 +4501,7 @@ msgstr "" msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" msgstr "" -#: part/templates/part/detail.html:11 part/templates/part/navbar.html:11 +#: part/templates/part/detail.html:11 part/templates/part/navbar.html:14 msgid "Part Details" msgstr "" @@ -4488,6 +4581,15 @@ msgstr "" msgid "Part is not active" msgstr "" +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:51 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Import Parts from File" +msgstr "" + #: part/templates/part/manufacturer.html:11 msgid "Part Manufacturers" msgstr "" @@ -4497,152 +4599,55 @@ msgid "Delete manufacturer parts" msgstr "" #: part/templates/part/manufacturer.html:53 -#: part/templates/part/supplier.html:57 +#: part/templates/part/supplier.html:56 msgid "Create new manufacturer" msgstr "" -#: part/templates/part/navbar.html:26 part/templates/part/variants.html:11 +#: part/templates/part/navbar.html:29 part/templates/part/variants.html:11 msgid "Part Variants" msgstr "" -#: part/templates/part/navbar.html:29 +#: part/templates/part/navbar.html:32 msgid "Variants" msgstr "" -#: part/templates/part/navbar.html:40 +#: part/templates/part/navbar.html:43 msgid "Allocated Stock" msgstr "" -#: part/templates/part/navbar.html:43 +#: part/templates/part/navbar.html:46 msgid "Allocations" msgstr "" -#: part/templates/part/navbar.html:64 part/templates/part/navbar.html:67 +#: part/templates/part/navbar.html:67 part/templates/part/navbar.html:70 msgid "Used In" msgstr "" -#: part/templates/part/navbar.html:72 part/templates/part/order_prices.html:12 -msgid "Order Price Information" +#: part/templates/part/navbar.html:77 +msgid "Prices" msgstr "" -#: part/templates/part/navbar.html:75 -msgid "Order Price" -msgstr "" - -#: part/templates/part/navbar.html:98 -msgid "Sales Price Information" -msgstr "" - -#: part/templates/part/navbar.html:112 part/templates/part/part_tests.html:10 +#: part/templates/part/navbar.html:109 part/templates/part/part_tests.html:10 msgid "Part Test Templates" msgstr "" -#: part/templates/part/navbar.html:115 stock/templates/stock/item_base.html:409 +#: part/templates/part/navbar.html:112 stock/templates/stock/item_base.html:414 msgid "Tests" msgstr "" -#: part/templates/part/navbar.html:119 part/templates/part/navbar.html:122 +#: part/templates/part/navbar.html:117 part/templates/part/navbar.html:120 #: part/templates/part/related.html:10 msgid "Related Parts" msgstr "" -#: part/templates/part/navbar.html:131 part/templates/part/notes.html:12 +#: part/templates/part/navbar.html:130 part/templates/part/notes.html:12 msgid "Part Notes" msgstr "" -#: part/templates/part/order_prices.html:21 -msgid "Pricing ranges" -msgstr "" - -#: part/templates/part/order_prices.html:26 -#: part/templates/part/part_pricing.html:19 -msgid "Supplier Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:27 -#: part/templates/part/order_prices.html:52 -#: part/templates/part/order_prices.html:83 -#: part/templates/part/part_pricing.html:23 -#: part/templates/part/part_pricing.html:49 -#: part/templates/part/part_pricing.html:81 -msgid "Unit Cost" -msgstr "" - -#: part/templates/part/order_prices.html:34 -#: part/templates/part/order_prices.html:59 -#: part/templates/part/order_prices.html:88 -#: part/templates/part/part_pricing.html:29 -#: part/templates/part/part_pricing.html:55 -#: part/templates/part/part_pricing.html:85 -msgid "Total Cost" -msgstr "" - -#: part/templates/part/order_prices.html:42 -#: part/templates/part/part_pricing.html:37 -msgid "No supplier pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:51 -#: part/templates/part/order_prices.html:103 -#: part/templates/part/part_pricing.html:45 -msgid "BOM Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:67 -#: part/templates/part/part_pricing.html:63 -msgid "Note: BOM pricing is incomplete for this part" -msgstr "" - -#: part/templates/part/order_prices.html:74 -#: part/templates/part/part_pricing.html:70 -msgid "No BOM pricing available" -msgstr "" - -#: part/templates/part/order_prices.html:97 -#: part/templates/part/part_pricing.html:94 -msgid "No pricing information is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:113 -msgid "Stock Pricing" -msgstr "" - -#: part/templates/part/order_prices.html:121 -msgid "No stock pricing history is available for this part." -msgstr "" - -#: part/templates/part/order_prices.html:140 -#, python-format -msgid "Single Price - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:152 -#, python-format -msgid "Single Price Difference - %(currency)s" -msgstr "" - -#: part/templates/part/order_prices.html:163 -#, python-format -msgid "Part Single Price - %(currency)s" -msgstr "" - #: part/templates/part/params.html:17 msgid "Add new parameter" msgstr "" -#: part/templates/part/params.html:18 -#: templates/InvenTree/settings/category.html:29 -#: templates/InvenTree/settings/part.html:44 -msgid "New Parameter" -msgstr "" - -#: part/templates/part/params.html:28 -#: report/templates/report/inventree_test_report_base.html:90 -#: stock/models.py:1756 templates/InvenTree/settings/header.html:8 -#: templates/js/stock.js:137 -msgid "Value" -msgstr "" - #: part/templates/part/params.html:41 templates/InvenTree/settings/user.html:19 msgid "Edit" msgstr "" @@ -4659,8 +4664,8 @@ msgstr "" msgid "Part List" msgstr "" -#: part/templates/part/part_base.html:26 templates/js/company.js:156 -#: templates/js/company.js:254 templates/js/part.js:84 templates/js/part.js:161 +#: part/templates/part/part_base.html:26 templates/js/company.js:280 +#: templates/js/company.js:480 templates/js/part.js:84 templates/js/part.js:161 msgid "Inactive" msgstr "" @@ -4723,7 +4728,7 @@ msgstr "" msgid "In Stock" msgstr "" -#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:131 +#: part/templates/part/part_base.html:143 templates/InvenTree/index.html:132 msgid "Required for Build Orders" msgstr "" @@ -4735,23 +4740,95 @@ msgstr "" msgid "Allocated to Orders" msgstr "" -#: part/templates/part/part_base.html:172 templates/js/bom.js:323 +#: part/templates/part/part_base.html:172 templates/js/bom.js:316 msgid "Can Build" msgstr "" #: part/templates/part/part_base.html:178 templates/js/part.js:312 -#: templates/js/part.js:484 +#: templates/js/part.js:485 msgid "Building" msgstr "" -#: part/templates/part/part_base.html:265 +#: part/templates/part/part_base.html:285 part/templates/part/prices.html:131 msgid "Calculate" msgstr "" +#: part/templates/part/part_base.html:379 +msgid "Create New Part Category" +msgstr "" + +#: part/templates/part/part_base.html:387 +msgid "New Parent" +msgstr "" + +#: part/templates/part/part_base.html:435 +msgid "Edit Part" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:27 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:85 +#: part/templates/part/part_pricing.html:100 part/templates/part/prices.html:31 +#: part/templates/part/prices.html:58 part/templates/part/prices.html:90 +#: part/templates/part/prices.html:107 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:89 +#: part/templates/part/part_pricing.html:104 part/templates/part/prices.html:38 +#: part/templates/part/prices.html:65 part/templates/part/prices.html:95 +#: part/templates/part/prices.html:112 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:46 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:55 +#: part/templates/part/prices.html:235 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:66 part/templates/part/prices.html:73 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:73 part/templates/part/prices.html:80 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:82 part/templates/part/prices.html:89 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:113 +#: part/templates/part/prices.html:121 +msgid "No pricing information is available for this part." +msgstr "" + #: part/templates/part/part_tests.html:17 msgid "Add Test Template" msgstr "" +#: part/templates/part/part_tests.html:61 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:79 +msgid "Edit Test Result Template" +msgstr "" + +#: part/templates/part/part_tests.html:91 +msgid "Delete Test Result Template" +msgstr "" + #: part/templates/part/part_thumb.html:20 msgid "Select from existing images" msgstr "" @@ -4786,12 +4863,98 @@ msgstr "" msgid "There are %(count)s unique parts tracked for '%(full_name)s'. Deleting this part will permanently remove this tracking information." msgstr "" -#: part/templates/part/related.html:18 -msgid "Add Related" +#: part/templates/part/prices.html:12 +msgid "General Price Information" msgstr "" -#: part/templates/part/sale_prices.html:10 -msgid "Sell Price Information" +#: part/templates/part/prices.html:22 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:28 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:29 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:56 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:104 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:105 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:127 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:146 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:147 part/templates/part/prices.html:167 +#: part/templates/part/prices.html:193 part/templates/part/prices.html:224 +#: part/templates/part/prices.html:251 part/templates/part/prices.html:279 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:172 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:180 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:192 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:206 part/views.py:2859 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:223 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:250 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:290 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/prices.html:340 +#, python-format +msgid "Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:352 +#, python-format +msgid "Single Price Difference - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:364 +#, python-format +msgid "Part Single Price - %(currency)s" +msgstr "" + +#: part/templates/part/prices.html:464 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/related.html:18 +msgid "Add Related" msgstr "" #: part/templates/part/sales_orders.html:18 @@ -4816,7 +4979,7 @@ msgid "Showing stock for all variants of %(full_name)s" msgstr "" #: part/templates/part/stock_count.html:7 templates/js/bom.js:239 -#: templates/js/part.js:302 templates/js/part.js:488 +#: templates/js/part.js:302 templates/js/part.js:489 msgid "No Stock" msgstr "" @@ -4853,296 +5016,276 @@ msgstr "" msgid "New Variant" msgstr "" -#: part/templatetags/inventree_extras.py:98 +#: part/templatetags/inventree_extras.py:99 msgid "Unknown database" msgstr "" -#: part/views.py:90 +#: part/views.py:95 msgid "Add Related Part" msgstr "" -#: part/views.py:145 +#: part/views.py:150 msgid "Delete Related Part" msgstr "" -#: part/views.py:159 -msgid "Add part attachment" -msgstr "" - -#: part/views.py:212 templates/attachment_table.html:32 -msgid "Edit attachment" -msgstr "" - -#: part/views.py:216 -msgid "Part attachment updated" -msgstr "" - -#: part/views.py:231 -msgid "Delete Part Attachment" -msgstr "" - -#: part/views.py:239 -msgid "Deleted part attachment" -msgstr "" - -#: part/views.py:248 -msgid "Create Test Template" -msgstr "" - -#: part/views.py:275 -msgid "Edit Test Template" -msgstr "" - -#: part/views.py:289 -msgid "Delete Test Template" -msgstr "" - -#: part/views.py:296 +#: part/views.py:161 msgid "Set Part Category" msgstr "" -#: part/views.py:346 +#: part/views.py:211 #, python-brace-format msgid "Set category for {n} parts" msgstr "" -#: part/views.py:381 +#: part/views.py:246 msgid "Create Variant" msgstr "" -#: part/views.py:466 +#: part/views.py:331 msgid "Copied part" msgstr "" -#: part/views.py:520 part/views.py:658 +#: part/views.py:385 part/views.py:523 msgid "Possible matches exist - confirm creation of new part" msgstr "" -#: part/views.py:590 +#: part/views.py:455 msgid "Created new part" msgstr "" -#: part/views.py:914 +#: part/views.py:623 +msgid "Match References" +msgstr "" + +#: part/views.py:925 +msgid "None" +msgstr "" + +#: part/views.py:984 msgid "Part QR Code" msgstr "" -#: part/views.py:1016 -msgid "Upload Part Image" -msgstr "" - -#: part/views.py:1022 part/views.py:1057 -msgid "Updated part image" -msgstr "" - -#: part/views.py:1031 +#: part/views.py:1086 msgid "Select Part Image" msgstr "" -#: part/views.py:1060 +#: part/views.py:1112 +msgid "Updated part image" +msgstr "" + +#: part/views.py:1115 msgid "Part image not found" msgstr "" -#: part/views.py:1071 +#: part/views.py:1126 msgid "Edit Part Properties" msgstr "" -#: part/views.py:1106 +#: part/views.py:1161 msgid "Duplicate BOM" msgstr "" -#: part/views.py:1136 +#: part/views.py:1191 msgid "Confirm duplication of BOM from parent" msgstr "" -#: part/views.py:1157 +#: part/views.py:1212 msgid "Validate BOM" msgstr "" -#: part/views.py:1178 +#: part/views.py:1233 msgid "Confirm that the BOM is valid" msgstr "" -#: part/views.py:1189 +#: part/views.py:1244 msgid "Validated Bill of Materials" msgstr "" -#: part/views.py:1323 +#: part/views.py:1378 msgid "No BOM file provided" msgstr "" -#: part/views.py:1684 +#: part/views.py:1739 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1709 part/views.py:1712 +#: part/views.py:1764 part/views.py:1767 msgid "Select valid part" msgstr "" -#: part/views.py:1718 +#: part/views.py:1773 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1756 +#: part/views.py:1811 msgid "Select a part" msgstr "" -#: part/views.py:1762 +#: part/views.py:1817 msgid "Selected part creates a circular BOM" msgstr "" -#: part/views.py:1766 +#: part/views.py:1821 msgid "Specify quantity" msgstr "" -#: part/views.py:2028 +#: part/views.py:2083 msgid "Confirm Part Deletion" msgstr "" -#: part/views.py:2035 +#: part/views.py:2090 msgid "Part was deleted" msgstr "" -#: part/views.py:2044 +#: part/views.py:2099 msgid "Part Pricing" msgstr "" -#: part/views.py:2178 +#: part/views.py:2240 msgid "Create Part Parameter Template" msgstr "" -#: part/views.py:2188 +#: part/views.py:2250 msgid "Edit Part Parameter Template" msgstr "" -#: part/views.py:2195 +#: part/views.py:2257 msgid "Delete Part Parameter Template" msgstr "" -#: part/views.py:2203 +#: part/views.py:2265 msgid "Create Part Parameter" msgstr "" -#: part/views.py:2253 +#: part/views.py:2315 msgid "Edit Part Parameter" msgstr "" -#: part/views.py:2267 +#: part/views.py:2329 msgid "Delete Part Parameter" msgstr "" -#: part/views.py:2327 -msgid "Edit Part Category" -msgstr "" - -#: part/views.py:2365 +#: part/views.py:2427 msgid "Delete Part Category" msgstr "" -#: part/views.py:2371 +#: part/views.py:2433 msgid "Part category was deleted" msgstr "" -#: part/views.py:2423 +#: part/views.py:2485 msgid "Create Category Parameter Template" msgstr "" -#: part/views.py:2524 +#: part/views.py:2586 msgid "Edit Category Parameter Template" msgstr "" -#: part/views.py:2580 +#: part/views.py:2642 msgid "Delete Category Parameter Template" msgstr "" -#: part/views.py:2599 +#: part/views.py:2661 msgid "Create BOM Item" msgstr "" -#: part/views.py:2669 +#: part/views.py:2731 msgid "Edit BOM item" msgstr "" -#: part/views.py:2725 -msgid "Confim BOM item deletion" +#: part/views.py:2792 +msgid "Added new price break" msgstr "" -#: report/models.py:180 +#: part/views.py:2868 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:2876 +msgid "Delete Internal Price Break" +msgstr "" + +#: report/models.py:181 msgid "Template name" msgstr "" -#: report/models.py:186 +#: report/models.py:187 msgid "Report template file" msgstr "" -#: report/models.py:193 +#: report/models.py:194 msgid "Report template description" msgstr "" -#: report/models.py:199 +#: report/models.py:200 msgid "Report revision number (auto-increments)" msgstr "" -#: report/models.py:275 +#: report/models.py:291 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:298 msgid "Report template is enabled" msgstr "" -#: report/models.py:295 +#: report/models.py:318 msgid "StockItem query filters (comma-separated list of key=value pairs)" msgstr "" -#: report/models.py:303 +#: report/models.py:326 msgid "Include Installed Tests" msgstr "" -#: report/models.py:304 +#: report/models.py:327 msgid "Include test results for stock items installed inside assembled item" msgstr "" -#: report/models.py:347 +#: report/models.py:371 msgid "Build Filters" msgstr "" -#: report/models.py:348 +#: report/models.py:372 msgid "Build query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:385 +#: report/models.py:410 msgid "Part Filters" msgstr "" -#: report/models.py:386 +#: report/models.py:411 msgid "Part query filters (comma-separated list of key=value pairs" msgstr "" -#: report/models.py:416 +#: report/models.py:441 msgid "Purchase order query filters" msgstr "" -#: report/models.py:450 +#: report/models.py:475 msgid "Sales order query filters" msgstr "" -#: report/models.py:500 +#: report/models.py:525 msgid "Snippet" msgstr "" -#: report/models.py:501 +#: report/models.py:526 msgid "Report snippet file" msgstr "" -#: report/models.py:505 +#: report/models.py:530 msgid "Snippet file description" msgstr "" -#: report/models.py:540 +#: report/models.py:565 msgid "Asset" msgstr "" -#: report/models.py:541 +#: report/models.py:566 msgid "Report asset file" msgstr "" -#: report/models.py:544 +#: report/models.py:569 msgid "Asset file description" msgstr "" @@ -5164,17 +5307,17 @@ msgid "Test Results" msgstr "" #: report/templates/report/inventree_test_report_base.html:88 -#: stock/models.py:1744 +#: stock/models.py:1759 msgid "Test" msgstr "" #: report/templates/report/inventree_test_report_base.html:89 -#: stock/models.py:1750 +#: stock/models.py:1765 msgid "Result" msgstr "" #: report/templates/report/inventree_test_report_base.html:92 -#: templates/js/order.js:195 templates/js/stock.js:987 +#: templates/js/order.js:257 templates/js/stock.js:1026 msgid "Date" msgstr "" @@ -5186,287 +5329,287 @@ msgstr "" msgid "Fail" msgstr "" -#: stock/api.py:212 +#: stock/api.py:211 #, python-brace-format msgid "Updated stock for {n} items" msgstr "" -#: stock/api.py:281 +#: stock/api.py:280 #, python-brace-format msgid "Moved {n} parts to {loc}" msgstr "" -#: stock/forms.py:114 stock/forms.py:418 stock/models.py:509 -#: stock/templates/stock/item_base.html:376 templates/js/stock.js:654 +#: stock/forms.py:81 stock/forms.py:385 stock/models.py:513 +#: stock/templates/stock/item_base.html:381 templates/js/stock.js:658 msgid "Expiry Date" msgstr "" -#: stock/forms.py:115 stock/forms.py:419 +#: stock/forms.py:82 stock/forms.py:386 msgid "Expiration date for this stock item" msgstr "" -#: stock/forms.py:118 +#: stock/forms.py:85 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: stock/forms.py:169 +#: stock/forms.py:136 msgid "Destination for serialized stock (by default, will remain in current location)" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Serial numbers" msgstr "" -#: stock/forms.py:171 +#: stock/forms.py:138 msgid "Unique serial numbers (must match quantity)" msgstr "" -#: stock/forms.py:173 stock/forms.py:349 +#: stock/forms.py:140 stock/forms.py:316 msgid "Add transaction note (optional)" msgstr "" -#: stock/forms.py:203 stock/forms.py:259 +#: stock/forms.py:170 stock/forms.py:226 msgid "Select test report template" msgstr "" -#: stock/forms.py:267 templates/js/table_filters.js:75 +#: stock/forms.py:234 templates/js/table_filters.js:75 #: templates/js/table_filters.js:138 msgid "Include sublocations" msgstr "" -#: stock/forms.py:267 +#: stock/forms.py:234 msgid "Include stock items in sub locations" msgstr "" -#: stock/forms.py:302 +#: stock/forms.py:269 msgid "Stock item to install" msgstr "" -#: stock/forms.py:309 +#: stock/forms.py:276 msgid "Stock quantity to assign" msgstr "" -#: stock/forms.py:337 +#: stock/forms.py:304 msgid "Must not exceed available quantity" msgstr "" -#: stock/forms.py:347 +#: stock/forms.py:314 msgid "Destination location for uninstalled items" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm uninstall" msgstr "" -#: stock/forms.py:351 +#: stock/forms.py:318 msgid "Confirm removal of installed stock items" msgstr "" -#: stock/forms.py:375 +#: stock/forms.py:342 msgid "Destination stock location" msgstr "" -#: stock/forms.py:377 +#: stock/forms.py:344 msgid "Add note (required)" msgstr "" -#: stock/forms.py:381 stock/views.py:852 stock/views.py:1051 +#: stock/forms.py:348 stock/views.py:705 stock/views.py:904 msgid "Confirm stock adjustment" msgstr "" -#: stock/forms.py:381 +#: stock/forms.py:348 msgid "Confirm movement of stock items" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set Default Location" msgstr "" -#: stock/forms.py:383 +#: stock/forms.py:350 msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:56 stock/models.py:547 +#: stock/models.py:56 stock/models.py:550 msgid "Owner" msgstr "" -#: stock/models.py:57 stock/models.py:548 +#: stock/models.py:57 stock/models.py:551 msgid "Select Owner" msgstr "" -#: stock/models.py:275 +#: stock/models.py:279 msgid "StockItem with this serial number already exists" msgstr "" -#: stock/models.py:311 +#: stock/models.py:315 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:321 stock/models.py:330 +#: stock/models.py:325 stock/models.py:334 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:322 +#: stock/models.py:326 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:344 +#: stock/models.py:348 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:350 +#: stock/models.py:354 msgid "Item must have a build reference if is_building=True" msgstr "" -#: stock/models.py:357 +#: stock/models.py:361 msgid "Build reference does not point to the same part object" msgstr "" -#: stock/models.py:399 +#: stock/models.py:403 msgid "Parent Stock Item" msgstr "" -#: stock/models.py:408 +#: stock/models.py:412 msgid "Base part" msgstr "" -#: stock/models.py:417 +#: stock/models.py:421 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:422 stock/templates/stock/stock_app_base.html:8 +#: stock/models.py:426 stock/templates/stock/stock_app_base.html:8 msgid "Stock Location" msgstr "" -#: stock/models.py:425 +#: stock/models.py:429 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:432 +#: stock/models.py:436 msgid "Packaging this stock item is stored in" msgstr "" -#: stock/models.py:437 stock/templates/stock/item_base.html:270 +#: stock/models.py:441 stock/templates/stock/item_base.html:270 msgid "Installed In" msgstr "" -#: stock/models.py:440 +#: stock/models.py:444 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:456 +#: stock/models.py:460 msgid "Serial number for this item" msgstr "" -#: stock/models.py:468 +#: stock/models.py:472 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:472 +#: stock/models.py:476 msgid "Stock Quantity" msgstr "" -#: stock/models.py:481 +#: stock/models.py:485 msgid "Source Build" msgstr "" -#: stock/models.py:483 +#: stock/models.py:487 msgid "Build for this stock item" msgstr "" -#: stock/models.py:494 +#: stock/models.py:498 msgid "Source Purchase Order" msgstr "" -#: stock/models.py:497 +#: stock/models.py:501 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:503 +#: stock/models.py:507 msgid "Destination Sales Order" msgstr "" -#: stock/models.py:510 +#: stock/models.py:514 msgid "Expiry date for stock item. Stock will be considered expired after this date" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete on deplete" msgstr "" -#: stock/models.py:523 +#: stock/models.py:527 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:533 stock/templates/stock/item_notes.html:13 +#: stock/models.py:537 stock/templates/stock/item_notes.html:13 #: stock/templates/stock/navbar.html:54 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:543 +#: stock/models.py:546 msgid "Single unit purchase price at time of purchase" msgstr "" -#: stock/models.py:1011 +#: stock/models.py:1014 msgid "Part is not set as trackable" msgstr "" -#: stock/models.py:1017 +#: stock/models.py:1020 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:1023 +#: stock/models.py:1026 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:1026 +#: stock/models.py:1029 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:1029 +#: stock/models.py:1032 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:1036 +#: stock/models.py:1039 #, python-brace-format msgid "Serial numbers already exist: {exists}" msgstr "" -#: stock/models.py:1194 +#: stock/models.py:1197 msgid "StockItem cannot be moved as it is not in stock" msgstr "" -#: stock/models.py:1668 +#: stock/models.py:1679 msgid "Entry notes" msgstr "" -#: stock/models.py:1721 +#: stock/models.py:1736 msgid "Value must be provided for this test" msgstr "" -#: stock/models.py:1727 +#: stock/models.py:1742 msgid "Attachment must be uploaded for this test" msgstr "" -#: stock/models.py:1745 +#: stock/models.py:1760 msgid "Test name" msgstr "" -#: stock/models.py:1751 templates/js/table_filters.js:217 +#: stock/models.py:1766 templates/js/table_filters.js:222 msgid "Test result" msgstr "" -#: stock/models.py:1757 +#: stock/models.py:1772 msgid "Test output value" msgstr "" -#: stock/models.py:1764 +#: stock/models.py:1779 msgid "Test result attachment" msgstr "" -#: stock/models.py:1770 +#: stock/models.py:1785 msgid "Test notes" msgstr "" @@ -5483,12 +5626,12 @@ msgid "Stock Item Attachments" msgstr "" #: stock/templates/stock/item_base.html:33 -#: stock/templates/stock/item_base.html:380 templates/js/table_filters.js:150 +#: stock/templates/stock/item_base.html:385 templates/js/table_filters.js:150 msgid "Expired" msgstr "" #: stock/templates/stock/item_base.html:43 -#: stock/templates/stock/item_base.html:382 templates/js/table_filters.js:155 +#: stock/templates/stock/item_base.html:387 templates/js/table_filters.js:155 msgid "Stale" msgstr "" @@ -5618,7 +5761,7 @@ msgstr "" msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item_base.html:289 templates/js/build.js:508 +#: stock/templates/stock/item_base.html:289 templates/js/build.js:594 msgid "No location set" msgstr "" @@ -5630,28 +5773,36 @@ msgstr "" msgid "Parent Item" msgstr "" -#: stock/templates/stock/item_base.html:380 +#: stock/templates/stock/item_base.html:356 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:385 #, python-format msgid "This StockItem expired on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:382 +#: stock/templates/stock/item_base.html:387 #, python-format msgid "This StockItem expires on %(item.expiry_date)s" msgstr "" -#: stock/templates/stock/item_base.html:389 templates/js/stock.js:660 +#: stock/templates/stock/item_base.html:394 templates/js/stock.js:664 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item_base.html:394 +#: stock/templates/stock/item_base.html:399 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item_base.html:398 +#: stock/templates/stock/item_base.html:403 msgid "No stocktake performed" msgstr "" +#: stock/templates/stock/item_base.html:499 +msgid "Edit Stock Status" +msgstr "" + #: stock/templates/stock/item_childs.html:12 msgid "Child Stock Items" msgstr "" @@ -5711,6 +5862,19 @@ msgstr "" msgid "Add Test Data" msgstr "" +#: stock/templates/stock/item_tests.html:86 +#: stock/templates/stock/item_tests.html:111 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:131 +msgid "Edit Test Result" +msgstr "" + +#: stock/templates/stock/item_tests.html:145 +msgid "Delete Test Result" +msgstr "" + #: stock/templates/stock/location.html:20 msgid "You are not in the list of owners of this location. This stock location cannot be edited." msgstr "" @@ -5759,7 +5923,7 @@ msgid "Stock Details" msgstr "" #: stock/templates/stock/location.html:117 templates/InvenTree/search.html:279 -#: templates/stats.html:97 users/models.py:41 +#: templates/stats.html:97 users/models.py:42 msgid "Stock Locations" msgstr "" @@ -5799,7 +5963,7 @@ msgstr "" msgid "The following stock items will be uninstalled" msgstr "" -#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1364 +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:1196 msgid "Convert Stock Item" msgstr "" @@ -5832,8 +5996,8 @@ msgstr "" msgid "Edit Stock Location" msgstr "" -#: stock/views.py:230 stock/views.py:1343 stock/views.py:1465 -#: stock/views.py:1830 +#: stock/views.py:230 stock/views.py:1175 stock/views.py:1297 +#: stock/views.py:1662 msgid "Owner is required (ownership control is enabled)" msgstr "" @@ -5841,205 +6005,177 @@ msgstr "" msgid "Stock Location QR code" msgstr "" -#: stock/views.py:265 -msgid "Add Stock Item Attachment" -msgstr "" - -#: stock/views.py:311 -msgid "Edit Stock Item Attachment" -msgstr "" - -#: stock/views.py:327 -msgid "Delete Stock Item Attachment" -msgstr "" - -#: stock/views.py:343 +#: stock/views.py:264 msgid "Assign to Customer" msgstr "" -#: stock/views.py:352 +#: stock/views.py:273 msgid "Customer must be specified" msgstr "" -#: stock/views.py:376 +#: stock/views.py:297 msgid "Return to Stock" msgstr "" -#: stock/views.py:385 +#: stock/views.py:306 msgid "Specify a valid location" msgstr "" -#: stock/views.py:396 +#: stock/views.py:317 msgid "Stock item returned from customer" msgstr "" -#: stock/views.py:407 +#: stock/views.py:328 msgid "Delete All Test Data" msgstr "" -#: stock/views.py:424 +#: stock/views.py:345 msgid "Confirm test data deletion" msgstr "" -#: stock/views.py:444 -msgid "Add Test Result" -msgstr "" - -#: stock/views.py:484 -msgid "Edit Test Result" -msgstr "" - -#: stock/views.py:501 -msgid "Delete Test Result" -msgstr "" - -#: stock/views.py:509 +#: stock/views.py:362 msgid "Stock Export Options" msgstr "" -#: stock/views.py:630 +#: stock/views.py:483 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:656 +#: stock/views.py:509 msgid "Install Stock Item" msgstr "" -#: stock/views.py:755 +#: stock/views.py:608 msgid "Uninstall Stock Items" msgstr "" -#: stock/views.py:863 +#: stock/views.py:716 msgid "Uninstalled stock items" msgstr "" -#: stock/views.py:888 +#: stock/views.py:741 msgid "Adjust Stock" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move Stock Items" msgstr "" -#: stock/views.py:998 +#: stock/views.py:851 msgid "Move" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count Stock Items" msgstr "" -#: stock/views.py:999 +#: stock/views.py:852 msgid "Count" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Remove From Stock" msgstr "" -#: stock/views.py:1000 +#: stock/views.py:853 msgid "Take" msgstr "" -#: stock/views.py:1001 +#: stock/views.py:854 msgid "Add Stock Items" msgstr "" -#: stock/views.py:1001 users/models.py:183 +#: stock/views.py:854 users/models.py:188 msgid "Add" msgstr "" -#: stock/views.py:1002 +#: stock/views.py:855 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:1031 +#: stock/views.py:884 msgid "Must enter integer value" msgstr "" -#: stock/views.py:1036 +#: stock/views.py:889 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:1043 +#: stock/views.py:896 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:1107 +#: stock/views.py:960 msgid "No action performed" msgstr "" -#: stock/views.py:1122 +#: stock/views.py:975 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:1137 +#: stock/views.py:990 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:1150 +#: stock/views.py:1003 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:1190 +#: stock/views.py:1043 msgid "No items were moved" msgstr "" -#: stock/views.py:1193 +#: stock/views.py:1046 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:1212 +#: stock/views.py:1065 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:1222 -msgid "Edit Stock Item Status" -msgstr "" - -#: stock/views.py:1245 +#: stock/views.py:1077 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:1482 +#: stock/views.py:1314 msgid "Serialize Stock" msgstr "" -#: stock/views.py:1575 templates/js/build.js:244 +#: stock/views.py:1407 templates/js/build.js:327 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:1717 +#: stock/views.py:1549 msgid "Duplicate Stock Item" msgstr "" -#: stock/views.py:1799 +#: stock/views.py:1631 msgid "Quantity cannot be negative" msgstr "" -#: stock/views.py:1899 +#: stock/views.py:1731 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:1912 +#: stock/views.py:1744 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:1923 +#: stock/views.py:1755 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:1930 +#: stock/views.py:1762 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:1939 +#: stock/views.py:1771 msgid "Add Stock Tracking Entry" msgstr "" @@ -6079,35 +6215,39 @@ msgstr "" msgid "Recently Updated" msgstr "" -#: templates/InvenTree/index.html:145 -msgid "Expired Stock" +#: templates/InvenTree/index.html:131 +msgid "Depleted Stock" msgstr "" #: templates/InvenTree/index.html:146 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:147 msgid "Stale Stock" msgstr "" -#: templates/InvenTree/index.html:184 +#: templates/InvenTree/index.html:192 msgid "Build Orders In Progress" msgstr "" -#: templates/InvenTree/index.html:185 +#: templates/InvenTree/index.html:193 msgid "Overdue Build Orders" msgstr "" -#: templates/InvenTree/index.html:206 +#: templates/InvenTree/index.html:214 msgid "Outstanding Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:207 +#: templates/InvenTree/index.html:215 msgid "Overdue Purchase Orders" msgstr "" -#: templates/InvenTree/index.html:229 +#: templates/InvenTree/index.html:237 msgid "Outstanding Sales Orders" msgstr "" -#: templates/InvenTree/index.html:230 +#: templates/InvenTree/index.html:238 msgid "Overdue Sales Orders" msgstr "" @@ -6119,11 +6259,11 @@ msgstr "" msgid "Enter a search query" msgstr "" -#: templates/InvenTree/search.html:268 templates/js/stock.js:298 +#: templates/InvenTree/search.html:268 templates/js/stock.js:303 msgid "Shipped to customer" msgstr "" -#: templates/InvenTree/search.html:271 templates/js/stock.js:308 +#: templates/InvenTree/search.html:271 templates/js/stock.js:313 msgid "No stock location set" msgstr "" @@ -6168,12 +6308,12 @@ msgid "No category parameter templates found" msgstr "" #: templates/InvenTree/settings/category.html:70 -#: templates/InvenTree/settings/part.html:81 +#: templates/InvenTree/settings/part.html:102 msgid "Edit Template" msgstr "" #: templates/InvenTree/settings/category.html:71 -#: templates/InvenTree/settings/part.html:82 +#: templates/InvenTree/settings/part.html:103 msgid "Delete Template" msgstr "" @@ -6181,23 +6321,23 @@ msgstr "" msgid "Currency Settings" msgstr "" -#: templates/InvenTree/settings/currencies.html:18 +#: templates/InvenTree/settings/currencies.html:25 msgid "Base Currency" msgstr "" -#: templates/InvenTree/settings/currencies.html:22 +#: templates/InvenTree/settings/currencies.html:29 msgid "Exchange Rates" msgstr "" -#: templates/InvenTree/settings/currencies.html:32 +#: templates/InvenTree/settings/currencies.html:39 msgid "Last Update" msgstr "" -#: templates/InvenTree/settings/currencies.html:38 +#: templates/InvenTree/settings/currencies.html:45 msgid "Never" msgstr "" -#: templates/InvenTree/settings/currencies.html:43 +#: templates/InvenTree/settings/currencies.html:50 msgid "Update Now" msgstr "" @@ -6221,11 +6361,19 @@ msgstr "" msgid "Part Options" msgstr "" -#: templates/InvenTree/settings/part.html:40 -msgid "Part Parameter Templates" +#: templates/InvenTree/settings/part.html:45 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" msgstr "" #: templates/InvenTree/settings/part.html:61 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/part.html:82 msgid "No part parameter templates found" msgstr "" @@ -6341,63 +6489,55 @@ msgid "API Version" msgstr "" #: templates/about.html:39 +msgid "Python Version" +msgstr "" + +#: templates/about.html:44 msgid "Django Version" msgstr "" -#: templates/about.html:46 +#: templates/about.html:51 msgid "Commit Hash" msgstr "" -#: templates/about.html:53 +#: templates/about.html:58 msgid "Commit Date" msgstr "" -#: templates/about.html:58 +#: templates/about.html:63 msgid "InvenTree Documentation" msgstr "" -#: templates/about.html:63 +#: templates/about.html:68 msgid "View Code on GitHub" msgstr "" -#: templates/about.html:68 +#: templates/about.html:73 msgid "Credits" msgstr "" -#: templates/about.html:73 +#: templates/about.html:78 msgid "Mobile App" msgstr "" -#: templates/about.html:78 +#: templates/about.html:83 msgid "Submit Bug Report" msgstr "" -#: templates/about.html:85 templates/clip.html:4 +#: templates/about.html:90 templates/clip.html:4 msgid "copy to clipboard" msgstr "" -#: templates/about.html:85 +#: templates/about.html:90 msgid "copy version information" msgstr "" -#: templates/about.html:95 templates/js/modals.js:568 -#: templates/js/modals.js:846 templates/modals.html:29 templates/modals.html:54 -#: templates/modals.html:97 +#: templates/about.html:100 templates/js/modals.js:34 +#: templates/js/modals.js:677 templates/js/modals.js:970 +#: templates/modals.html:29 templates/modals.html:54 templates/modals.html:97 msgid "Close" msgstr "" -#: templates/attachment_table.html:6 -msgid "Add Attachment" -msgstr "" - -#: templates/attachment_table.html:17 -msgid "Uploaded" -msgstr "" - -#: templates/attachment_table.html:35 -msgid "Delete attachment" -msgstr "" - #: templates/image_download.html:8 msgid "Specify URL for downloading image" msgstr "" @@ -6414,6 +6554,22 @@ msgstr "" msgid "Remote image must not exceed maximum allowable file size" msgstr "" +#: templates/js/attachment.js:16 +msgid "No attachments found" +msgstr "" + +#: templates/js/attachment.js:56 +msgid "Upload Date" +msgstr "" + +#: templates/js/attachment.js:69 +msgid "Edit attachment" +msgstr "" + +#: templates/js/attachment.js:76 +msgid "Delete attachment" +msgstr "" + #: templates/js/barcode.js:8 msgid "Scan barcode data here using wedge scanner" msgstr "" @@ -6442,7 +6598,7 @@ msgstr "" msgid "Unknown response from server" msgstr "" -#: templates/js/barcode.js:119 templates/js/modals.js:901 +#: templates/js/barcode.js:119 templates/js/modals.js:1030 msgid "Invalid server response" msgstr "" @@ -6506,7 +6662,7 @@ msgstr "" msgid "Barcode does not match a valid location" msgstr "" -#: templates/js/bom.js:175 templates/js/build.js:1004 +#: templates/js/bom.js:175 templates/js/build.js:1092 msgid "Open subassembly" msgstr "" @@ -6518,31 +6674,35 @@ msgstr "" msgid "Purchase Price Average" msgstr "" -#: templates/js/bom.js:277 +#: templates/js/bom.js:265 +msgid "Buy Price" +msgstr "" + +#: templates/js/bom.js:271 msgid "No pricing available" msgstr "" -#: templates/js/bom.js:313 templates/js/bom.js:399 +#: templates/js/bom.js:306 templates/js/bom.js:392 msgid "View BOM" msgstr "" -#: templates/js/bom.js:373 +#: templates/js/bom.js:366 msgid "Validate BOM Item" msgstr "" -#: templates/js/bom.js:375 +#: templates/js/bom.js:368 msgid "This line has been validated" msgstr "" -#: templates/js/bom.js:377 +#: templates/js/bom.js:370 msgid "Edit BOM Item" msgstr "" -#: templates/js/bom.js:379 +#: templates/js/bom.js:372 templates/js/bom.js:519 msgid "Delete BOM Item" msgstr "" -#: templates/js/bom.js:470 templates/js/build.js:340 templates/js/build.js:1102 +#: templates/js/bom.js:463 templates/js/build.js:424 templates/js/build.js:1190 msgid "No BOM items found" msgstr "" @@ -6562,67 +6722,111 @@ msgstr "" msgid "Delete build output" msgstr "" -#: templates/js/build.js:243 templates/stock_table.html:20 +#: templates/js/build.js:184 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/build.js:222 templates/js/order.js:449 +msgid "Location not specified" +msgstr "" + +#: templates/js/build.js:326 templates/stock_table.html:20 msgid "New Stock Item" msgstr "" -#: templates/js/build.js:559 +#: templates/js/build.js:645 msgid "Required Part" msgstr "" -#: templates/js/build.js:580 +#: templates/js/build.js:666 msgid "Quantity Per" msgstr "" -#: templates/js/build.js:648 templates/js/build.js:1066 +#: templates/js/build.js:736 templates/js/build.js:1154 #: templates/stock_table.html:59 msgid "Order stock" msgstr "" -#: templates/js/build.js:701 +#: templates/js/build.js:789 msgid "No builds matching query" msgstr "" -#: templates/js/build.js:718 templates/js/part.js:390 templates/js/part.js:634 -#: templates/js/stock.js:509 templates/js/stock.js:941 +#: templates/js/build.js:806 templates/js/part.js:390 templates/js/part.js:635 +#: templates/js/stock.js:514 templates/js/stock.js:980 msgid "Select" msgstr "" -#: templates/js/build.js:738 +#: templates/js/build.js:826 msgid "Build order is overdue" msgstr "" -#: templates/js/build.js:837 +#: templates/js/build.js:925 msgid "No parts allocated for" msgstr "" -#: templates/js/company.js:74 +#: templates/js/company.js:45 +msgid "Edit Company" +msgstr "" + +#: templates/js/company.js:66 +msgid "Add new Company" +msgstr "" + +#: templates/js/company.js:143 msgid "Parts Supplied" msgstr "" -#: templates/js/company.js:83 +#: templates/js/company.js:152 msgid "Parts Manufactured" msgstr "" -#: templates/js/company.js:96 +#: templates/js/company.js:165 msgid "No company information found" msgstr "" -#: templates/js/company.js:129 +#: templates/js/company.js:183 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/company.js:200 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/company.js:253 msgid "No manufacturer parts found" msgstr "" -#: templates/js/company.js:148 templates/js/company.js:246 +#: templates/js/company.js:272 templates/js/company.js:472 #: templates/js/part.js:68 templates/js/part.js:153 msgid "Template part" msgstr "" -#: templates/js/company.js:152 templates/js/company.js:250 +#: templates/js/company.js:276 templates/js/company.js:476 #: templates/js/part.js:72 templates/js/part.js:157 msgid "Assembled part" msgstr "" -#: templates/js/company.js:227 +#: templates/js/company.js:350 +msgid "No parameters found" +msgstr "" + +#: templates/js/company.js:386 +msgid "Edit parameter" +msgstr "" + +#: templates/js/company.js:387 +msgid "Delete parameter" +msgstr "" + +#: templates/js/company.js:406 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/company.js:417 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/company.js:453 msgid "No supplier parts found" msgstr "" @@ -6650,6 +6854,83 @@ msgstr "" msgid "Create filter" msgstr "" +#: templates/js/forms.js:278 templates/js/forms.js:291 +#: templates/js/forms.js:303 templates/js/forms.js:315 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/forms.js:279 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/forms.js:292 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/forms.js:304 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/forms.js:316 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/forms.js:583 templates/js/modals.js:1040 +msgid "No Response" +msgstr "" + +#: templates/js/forms.js:584 templates/js/modals.js:1041 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/forms.js:590 templates/js/modals.js:1050 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/forms.js:591 templates/js/modals.js:1051 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/forms.js:597 templates/js/modals.js:1055 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/forms.js:598 templates/js/modals.js:1056 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/forms.js:604 templates/js/modals.js:1060 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/forms.js:605 templates/js/modals.js:1061 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/forms.js:611 templates/js/modals.js:1065 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/forms.js:612 templates/js/modals.js:1066 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/forms.js:618 templates/js/modals.js:1069 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/forms.js:788 templates/modals.html:21 templates/modals.html:47 +msgid "Form errors exist" +msgstr "" + +#: templates/js/forms.js:1161 +msgid "Searching" +msgstr "" + +#: templates/js/forms.js:1301 +msgid "Clear input" +msgstr "" + #: templates/js/label.js:10 templates/js/report.js:98 msgid "Select Stock Items" msgstr "" @@ -6690,111 +6971,105 @@ msgstr "" msgid "Select Label Template" msgstr "" -#: templates/js/modals.js:265 -msgid "Waiting for server..." -msgstr "" - -#: templates/js/modals.js:424 -msgid "Show Error Information" -msgstr "" - -#: templates/js/modals.js:491 templates/modals.html:76 -msgid "Accept" -msgstr "" - -#: templates/js/modals.js:492 templates/modals.html:75 +#: templates/js/modals.js:59 templates/js/modals.js:105 +#: templates/js/modals.js:601 templates/modals.html:75 msgid "Cancel" msgstr "" -#: templates/js/modals.js:556 -msgid "Loading Data" -msgstr "" - -#: templates/js/modals.js:567 templates/js/modals.js:845 +#: templates/js/modals.js:60 templates/js/modals.js:104 +#: templates/js/modals.js:676 templates/js/modals.js:969 #: templates/modals.html:30 templates/modals.html:55 msgid "Submit" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:103 +msgid "Form Title" +msgstr "" + +#: templates/js/modals.js:374 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/modals.js:533 +msgid "Show Error Information" +msgstr "" + +#: templates/js/modals.js:600 templates/modals.html:76 +msgid "Accept" +msgstr "" + +#: templates/js/modals.js:665 +msgid "Loading Data" +msgstr "" + +#: templates/js/modals.js:920 msgid "Invalid response from server" msgstr "" -#: templates/js/modals.js:797 +#: templates/js/modals.js:920 msgid "Form data missing from server response" msgstr "" -#: templates/js/modals.js:810 +#: templates/js/modals.js:933 msgid "Error posting form data" msgstr "" -#: templates/js/modals.js:901 +#: templates/js/modals.js:1030 msgid "JSON response missing form data" msgstr "" -#: templates/js/modals.js:911 -msgid "No Response" -msgstr "" - -#: templates/js/modals.js:912 -msgid "No response from the InvenTree server" -msgstr "" - -#: templates/js/modals.js:916 +#: templates/js/modals.js:1045 msgid "Error 400: Bad Request" msgstr "" -#: templates/js/modals.js:917 +#: templates/js/modals.js:1046 msgid "Server returned error code 400" msgstr "" -#: templates/js/modals.js:921 -msgid "Error 401: Not Authenticated" +#: templates/js/model_renderers.js:21 +msgid "Company ID" msgstr "" -#: templates/js/modals.js:922 -msgid "Authentication credentials not supplied" +#: templates/js/model_renderers.js:63 +msgid "Location ID" msgstr "" -#: templates/js/modals.js:926 -msgid "Error 403: Permission Denied" +#: templates/js/model_renderers.js:90 +msgid "Part ID" msgstr "" -#: templates/js/modals.js:927 -msgid "You do not have the required permissions to access this function" +#: templates/js/model_renderers.js:126 +msgid "Category ID" msgstr "" -#: templates/js/modals.js:931 -msgid "Error 404: Resource Not Found" +#: templates/js/model_renderers.js:150 +msgid "Supplier Part ID" msgstr "" -#: templates/js/modals.js:932 -msgid "The requested resource could not be located on the server" +#: templates/js/order.js:31 +msgid "Create Sales Order" msgstr "" -#: templates/js/modals.js:936 -msgid "Error 408: Timeout" -msgstr "" - -#: templates/js/modals.js:937 -msgid "Connection timeout while requesting data from server" -msgstr "" - -#: templates/js/modals.js:940 -msgid "Error requesting form data" -msgstr "" - -#: templates/js/order.js:138 +#: templates/js/order.js:200 msgid "No purchase orders found" msgstr "" -#: templates/js/order.js:162 templates/js/order.js:257 +#: templates/js/order.js:224 templates/js/order.js:319 msgid "Order is overdue" msgstr "" -#: templates/js/order.js:234 +#: templates/js/order.js:296 msgid "No sales orders found" msgstr "" +#: templates/js/order.js:333 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/order.js:410 +msgid "No sales order allocations found" +msgstr "" + #: templates/js/part.js:10 msgid "YES" msgstr "" @@ -6823,39 +7098,54 @@ msgstr "" msgid "No variants found" msgstr "" -#: templates/js/part.js:280 templates/js/part.js:518 +#: templates/js/part.js:280 templates/js/part.js:519 msgid "No parts found" msgstr "" -#: templates/js/part.js:457 +#: templates/js/part.js:458 msgid "No category" msgstr "" -#: templates/js/part.js:475 templates/js/table_filters.js:323 +#: templates/js/part.js:476 templates/js/table_filters.js:328 msgid "Low stock" msgstr "" -#: templates/js/part.js:659 templates/js/stock.js:965 +#: templates/js/part.js:660 templates/js/stock.js:1004 msgid "Path" msgstr "" -#: templates/js/part.js:702 +#: templates/js/part.js:703 msgid "No test templates matching query" msgstr "" -#: templates/js/part.js:753 templates/js/stock.js:75 +#: templates/js/part.js:754 templates/js/stock.js:75 msgid "Edit test result" msgstr "" -#: templates/js/part.js:754 templates/js/stock.js:76 +#: templates/js/part.js:755 templates/js/stock.js:76 msgid "Delete test result" msgstr "" -#: templates/js/part.js:760 +#: templates/js/part.js:761 msgid "This test is defined for a parent part" msgstr "" -#: templates/js/part.js:805 +#: templates/js/part.js:786 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/part.js:839 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/part.js:840 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/part.js:959 msgid "Single Price Difference" msgstr "" @@ -6953,155 +7243,155 @@ msgstr "" msgid "Test Date" msgstr "" -#: templates/js/stock.js:290 +#: templates/js/stock.js:295 msgid "In production" msgstr "" -#: templates/js/stock.js:294 +#: templates/js/stock.js:299 msgid "Installed in Stock Item" msgstr "" -#: templates/js/stock.js:302 +#: templates/js/stock.js:307 msgid "Assigned to Sales Order" msgstr "" -#: templates/js/stock.js:334 +#: templates/js/stock.js:339 msgid "No stock items matching query" msgstr "" -#: templates/js/stock.js:355 +#: templates/js/stock.js:360 msgid "items" msgstr "" -#: templates/js/stock.js:447 +#: templates/js/stock.js:452 msgid "batches" msgstr "" -#: templates/js/stock.js:474 +#: templates/js/stock.js:479 msgid "locations" msgstr "" -#: templates/js/stock.js:476 +#: templates/js/stock.js:481 msgid "Undefined location" msgstr "" -#: templates/js/stock.js:577 +#: templates/js/stock.js:582 msgid "Stock item is in production" msgstr "" -#: templates/js/stock.js:582 +#: templates/js/stock.js:587 msgid "Stock item assigned to sales order" msgstr "" -#: templates/js/stock.js:585 +#: templates/js/stock.js:590 msgid "Stock item assigned to customer" msgstr "" -#: templates/js/stock.js:589 +#: templates/js/stock.js:594 msgid "Stock item has expired" msgstr "" -#: templates/js/stock.js:591 +#: templates/js/stock.js:596 msgid "Stock item will expire soon" msgstr "" -#: templates/js/stock.js:595 +#: templates/js/stock.js:600 msgid "Stock item has been allocated" msgstr "" -#: templates/js/stock.js:599 +#: templates/js/stock.js:604 msgid "Stock item has been installed in another item" msgstr "" -#: templates/js/stock.js:607 +#: templates/js/stock.js:611 msgid "Stock item has been rejected" msgstr "" -#: templates/js/stock.js:611 +#: templates/js/stock.js:615 msgid "Stock item is lost" msgstr "" -#: templates/js/stock.js:614 +#: templates/js/stock.js:618 msgid "Stock item is destroyed" msgstr "" -#: templates/js/stock.js:618 templates/js/table_filters.js:143 +#: templates/js/stock.js:622 templates/js/table_filters.js:143 msgid "Depleted" msgstr "" -#: templates/js/stock.js:647 +#: templates/js/stock.js:651 msgid "Stocktake" msgstr "" -#: templates/js/stock.js:828 +#: templates/js/stock.js:867 msgid "Stock Status" msgstr "" -#: templates/js/stock.js:843 +#: templates/js/stock.js:882 msgid "Set Stock Status" msgstr "" -#: templates/js/stock.js:857 +#: templates/js/stock.js:896 msgid "Select Status Code" msgstr "" -#: templates/js/stock.js:858 +#: templates/js/stock.js:897 msgid "Status code must be selected" msgstr "" -#: templates/js/stock.js:997 +#: templates/js/stock.js:1036 msgid "Invalid date" msgstr "" -#: templates/js/stock.js:1044 +#: templates/js/stock.js:1083 msgid "Location no longer exists" msgstr "" -#: templates/js/stock.js:1063 +#: templates/js/stock.js:1102 msgid "Purchase order no longer exists" msgstr "" -#: templates/js/stock.js:1082 +#: templates/js/stock.js:1121 msgid "Customer no longer exists" msgstr "" -#: templates/js/stock.js:1100 +#: templates/js/stock.js:1139 msgid "Stock item no longer exists" msgstr "" -#: templates/js/stock.js:1123 +#: templates/js/stock.js:1162 msgid "Added" msgstr "" -#: templates/js/stock.js:1131 +#: templates/js/stock.js:1170 msgid "Removed" msgstr "" -#: templates/js/stock.js:1163 +#: templates/js/stock.js:1202 msgid "No user information" msgstr "" -#: templates/js/stock.js:1175 +#: templates/js/stock.js:1214 msgid "Edit tracking entry" msgstr "" -#: templates/js/stock.js:1176 +#: templates/js/stock.js:1215 msgid "Delete tracking entry" msgstr "" -#: templates/js/stock.js:1300 +#: templates/js/stock.js:1339 msgid "Create New Location" msgstr "" -#: templates/js/stock.js:1341 +#: templates/js/stock.js:1380 msgid "No installed items" msgstr "" -#: templates/js/stock.js:1364 +#: templates/js/stock.js:1403 msgid "Serial" msgstr "" -#: templates/js/stock.js:1392 +#: templates/js/stock.js:1431 msgid "Uninstall Stock Item" msgstr "" @@ -7122,7 +7412,7 @@ msgid "Include locations" msgstr "" #: templates/js/table_filters.js:86 templates/js/table_filters.js:87 -#: templates/js/table_filters.js:300 +#: templates/js/table_filters.js:305 msgid "Include subcategories" msgstr "" @@ -7155,7 +7445,7 @@ msgstr "" msgid "Batch code" msgstr "" -#: templates/js/table_filters.js:123 templates/js/table_filters.js:290 +#: templates/js/table_filters.js:123 templates/js/table_filters.js:295 msgid "Active parts" msgstr "" @@ -7227,103 +7517,107 @@ msgstr "" msgid "Stock status" msgstr "" -#: templates/js/table_filters.js:236 +#: templates/js/table_filters.js:211 +msgid "Has purchase price" +msgstr "" + +#: templates/js/table_filters.js:212 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/table_filters.js:241 msgid "Build status" msgstr "" -#: templates/js/table_filters.js:255 templates/js/table_filters.js:272 +#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 msgid "Order status" msgstr "" -#: templates/js/table_filters.js:260 templates/js/table_filters.js:277 +#: templates/js/table_filters.js:265 templates/js/table_filters.js:282 msgid "Outstanding" msgstr "" -#: templates/js/table_filters.js:301 +#: templates/js/table_filters.js:306 msgid "Include parts in subcategories" msgstr "" -#: templates/js/table_filters.js:305 +#: templates/js/table_filters.js:310 msgid "Has IPN" msgstr "" -#: templates/js/table_filters.js:306 +#: templates/js/table_filters.js:311 msgid "Part has internal part number" msgstr "" -#: templates/js/table_filters.js:311 +#: templates/js/table_filters.js:316 msgid "Show active parts" msgstr "" -#: templates/js/table_filters.js:319 +#: templates/js/table_filters.js:324 msgid "Stock available" msgstr "" -#: templates/js/table_filters.js:335 +#: templates/js/table_filters.js:340 msgid "Starred" msgstr "" -#: templates/js/table_filters.js:347 +#: templates/js/table_filters.js:352 msgid "Purchasable" msgstr "" -#: templates/js/tables.js:321 +#: templates/js/tables.js:323 msgid "Loading data" msgstr "" -#: templates/js/tables.js:324 +#: templates/js/tables.js:326 msgid "rows per page" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "Showing" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "to" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "of" msgstr "" -#: templates/js/tables.js:327 +#: templates/js/tables.js:329 msgid "rows" msgstr "" -#: templates/js/tables.js:330 templates/search_form.html:6 +#: templates/js/tables.js:332 templates/search_form.html:6 #: templates/search_form.html:8 msgid "Search" msgstr "" -#: templates/js/tables.js:333 +#: templates/js/tables.js:335 msgid "No matching results" msgstr "" -#: templates/js/tables.js:336 +#: templates/js/tables.js:338 msgid "Hide/Show pagination" msgstr "" -#: templates/js/tables.js:339 +#: templates/js/tables.js:341 msgid "Refresh" msgstr "" -#: templates/js/tables.js:342 +#: templates/js/tables.js:344 msgid "Toggle" msgstr "" -#: templates/js/tables.js:345 +#: templates/js/tables.js:347 msgid "Columns" msgstr "" -#: templates/js/tables.js:348 +#: templates/js/tables.js:350 msgid "All" msgstr "" -#: templates/modals.html:21 templates/modals.html:47 -msgid "Form errors exist" -msgstr "" - #: templates/navbar.html:13 msgid "Toggle navigation" msgstr "" @@ -7340,7 +7634,7 @@ msgstr "" msgid "Scan Barcode" msgstr "" -#: templates/navbar.html:77 users/models.py:38 +#: templates/navbar.html:77 users/models.py:39 msgid "Admin" msgstr "" @@ -7560,35 +7854,35 @@ msgstr "" msgid "Important dates" msgstr "" -#: users/models.py:170 +#: users/models.py:175 msgid "Permission set" msgstr "" -#: users/models.py:178 +#: users/models.py:183 msgid "Group" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "View" msgstr "" -#: users/models.py:181 +#: users/models.py:186 msgid "Permission to view items" msgstr "" -#: users/models.py:183 +#: users/models.py:188 msgid "Permission to add items" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Change" msgstr "" -#: users/models.py:185 +#: users/models.py:190 msgid "Permissions to edit items" msgstr "" -#: users/models.py:187 +#: users/models.py:192 msgid "Permission to delete items" msgstr "" diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index 1e7b20e5a1..5d843fc624 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -15,6 +15,7 @@ from .models import SalesOrderAllocation class PurchaseOrderLineItemInlineAdmin(admin.StackedInline): model = PurchaseOrderLineItem + extra = 0 class PurchaseOrderAdmin(ImportExportModelAdmin): diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index c22d76a52e..a834989fd9 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -5,11 +5,12 @@ JSON API for the Order app # -*- coding: utf-8 -*- from __future__ import unicode_literals +from django.conf.urls import url, include + from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics -from rest_framework import filters - -from django.conf.urls import url, include +from rest_framework import filters, status +from rest_framework.response import Response from InvenTree.helpers import str2bool from InvenTree.api import AttachmentMixin @@ -38,6 +39,20 @@ class POList(generics.ListCreateAPIView): queryset = PurchaseOrder.objects.all() serializer_class = POSerializer + def create(self, request, *args, **kwargs): + """ + Save user information on create + """ + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + + item = serializer.save() + item.created_by = request.user + item.save() + + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + def get_serializer(self, *args, **kwargs): try: @@ -239,10 +254,12 @@ class POLineItemList(generics.ListCreateAPIView): ] -class POLineItemDetail(generics.RetrieveUpdateAPIView): - """ API endpoint for detail view of a PurchaseOrderLineItem object """ +class POLineItemDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail API endpoint for PurchaseOrderLineItem object + """ - queryset = PurchaseOrderLineItem + queryset = PurchaseOrderLineItem.objects.all() serializer_class = POLineItemSerializer @@ -254,11 +271,24 @@ class SOAttachmentList(generics.ListCreateAPIView, AttachmentMixin): queryset = SalesOrderAttachment.objects.all() serializer_class = SOAttachmentSerializer + filter_backends = [ + DjangoFilterBackend, + ] + filter_fields = [ 'order', ] +class SOAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for SalesOrderAttachment + """ + + queryset = SalesOrderAttachment.objects.all() + serializer_class = SOAttachmentSerializer + + class SOList(generics.ListCreateAPIView): """ API endpoint for accessing a list of SalesOrder objects. @@ -270,6 +300,20 @@ class SOList(generics.ListCreateAPIView): queryset = SalesOrder.objects.all() serializer_class = SalesOrderSerializer + def create(self, request, *args, **kwargs): + """ + Save user information on create + """ + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + + item = serializer.save() + item.created_by = request.user + item.save() + + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + def get_serializer(self, *args, **kwargs): try: @@ -474,7 +518,7 @@ class SOLineItemList(generics.ListCreateAPIView): ] -class SOLineItemDetail(generics.RetrieveUpdateAPIView): +class SOLineItemDetail(generics.RetrieveUpdateDestroyAPIView): """ API endpoint for detail view of a SalesOrderLineItem object """ queryset = SalesOrderLineItem.objects.all() @@ -553,13 +597,31 @@ class POAttachmentList(generics.ListCreateAPIView, AttachmentMixin): queryset = PurchaseOrderAttachment.objects.all() serializer_class = POAttachmentSerializer + filter_backends = [ + DjangoFilterBackend, + ] + + filter_fields = [ + 'order', + ] + + +class POAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for a PurchaseOrderAttachment + """ + + queryset = PurchaseOrderAttachment.objects.all() + serializer_class = POAttachmentSerializer + order_api_urls = [ # API endpoints for purchase orders - url(r'^po/(?P\d+)/$', PODetail.as_view(), name='api-po-detail'), url(r'po/attachment/', include([ + url(r'^(?P\d+)/$', POAttachmentDetail.as_view(), name='api-po-attachment-detail'), url(r'^.*$', POAttachmentList.as_view(), name='api-po-attachment-list'), ])), + url(r'^po/(?P\d+)/$', PODetail.as_view(), name='api-po-detail'), url(r'^po/.*$', POList.as_view(), name='api-po-list'), # API endpoints for purchase order line items @@ -568,12 +630,12 @@ order_api_urls = [ # API endpoints for sales ordesr url(r'^so/', include([ - url(r'^(?P\d+)/$', SODetail.as_view(), name='api-so-detail'), url(r'attachment/', include([ + url(r'^(?P\d+)/$', SOAttachmentDetail.as_view(), name='api-so-attachment-detail'), url(r'^.*$', SOAttachmentList.as_view(), name='api-so-attachment-list'), ])), - # List all sales orders + url(r'^(?P\d+)/$', SODetail.as_view(), name='api-so-detail'), url(r'^.*$', SOList.as_view(), name='api-so-list'), ])), diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index effa696d43..b8a66a825d 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -11,14 +11,17 @@ from django.utils.translation import ugettext_lazy as _ from mptt.fields import TreeNodeChoiceField from InvenTree.forms import HelperForm -from InvenTree.fields import RoundingDecimalFormField -from InvenTree.fields import DatePickerFormField +from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField + +from InvenTree.helpers import clean_decimal + +from common.forms import MatchItemForm import part.models from stock.models import StockLocation -from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment -from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment +from .models import PurchaseOrder +from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation @@ -93,135 +96,6 @@ class ReceivePurchaseOrderForm(HelperForm): ] -class EditPurchaseOrderForm(HelperForm): - """ Form for editing a PurchaseOrder object """ - - def __init__(self, *args, **kwargs): - - self.field_prefix = { - 'reference': 'PO', - 'link': 'fa-link', - 'target_date': 'fa-calendar-alt', - } - - self.field_placeholder = { - 'reference': _('Purchase Order reference'), - } - - super().__init__(*args, **kwargs) - - target_date = DatePickerFormField( - label=_('Target Date'), - help_text=_('Target date for order delivery. Order will be overdue after this date.'), - ) - - class Meta: - model = PurchaseOrder - fields = [ - 'reference', - 'supplier', - 'supplier_reference', - 'description', - 'target_date', - 'link', - 'responsible', - ] - - -class EditSalesOrderForm(HelperForm): - """ Form for editing a SalesOrder object """ - - def __init__(self, *args, **kwargs): - - self.field_prefix = { - 'reference': 'SO', - 'link': 'fa-link', - 'target_date': 'fa-calendar-alt', - } - - self.field_placeholder = { - 'reference': _('Enter sales order number'), - } - - super().__init__(*args, **kwargs) - - target_date = DatePickerFormField( - label=_('Target Date'), - help_text=_('Target date for order completion. Order will be overdue after this date.'), - ) - - class Meta: - model = SalesOrder - fields = [ - 'reference', - 'customer', - 'customer_reference', - 'description', - 'target_date', - 'link', - 'responsible', - ] - - -class EditPurchaseOrderAttachmentForm(HelperForm): - """ Form for editing a PurchaseOrderAttachment object """ - - class Meta: - model = PurchaseOrderAttachment - fields = [ - 'order', - 'attachment', - 'comment' - ] - - -class EditSalesOrderAttachmentForm(HelperForm): - """ Form for editing a SalesOrderAttachment object """ - - class Meta: - model = SalesOrderAttachment - fields = [ - 'order', - 'attachment', - 'comment' - ] - - -class EditPurchaseOrderLineItemForm(HelperForm): - """ Form for editing a PurchaseOrderLineItem object """ - - quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity')) - - class Meta: - model = PurchaseOrderLineItem - fields = [ - 'order', - 'part', - 'quantity', - 'reference', - 'purchase_price', - 'destination', - 'notes', - ] - - -class EditSalesOrderLineItemForm(HelperForm): - """ Form for editing a SalesOrderLineItem object """ - - quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity')) - - class Meta: - model = SalesOrderLineItem - fields = [ - 'order', - 'part', - 'quantity', - 'reference', - 'sale_price', - 'notes' - ] - - class AllocateSerialsToSalesOrderForm(forms.Form): """ Form for assigning stock to a sales order, @@ -291,3 +165,36 @@ class EditSalesOrderAllocationForm(HelperForm): 'line', 'item', 'quantity'] + + +class OrderMatchItemForm(MatchItemForm): + """ Override MatchItemForm fields """ + + def get_special_field(self, col_guess, row, file_manager): + """ Set special fields """ + + # set quantity field + if 'quantity' in col_guess.lower(): + return forms.CharField( + required=False, + widget=forms.NumberInput(attrs={ + 'name': 'quantity' + str(row['index']), + 'class': 'numberinput', + 'type': 'number', + 'min': '0', + 'step': 'any', + 'value': clean_decimal(row.get('quantity', '')), + }) + ) + # set price field + elif 'price' in col_guess.lower(): + return InvenTreeMoneyField( + label=_(col_guess), + decimal_places=5, + max_digits=19, + required=False, + default_amount=clean_decimal(row.get('purchase_price', '')), + ) + + # return default + return super().get_special_field(col_guess, row, file_manager) diff --git a/InvenTree/order/migrations/0047_auto_20210701_0509.py b/InvenTree/order/migrations/0047_auto_20210701_0509.py new file mode 100644 index 0000000000..1f732e5f61 --- /dev/null +++ b/InvenTree/order/migrations/0047_auto_20210701_0509.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0046_purchaseorderlineitem_destination'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorderlineitem', + name='purchase_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'), + ), + migrations.AlterField( + model_name='purchaseorderlineitem', + name='purchase_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + migrations.AlterField( + model_name='salesorderlineitem', + name='sale_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Unit sale price', max_digits=19, null=True, verbose_name='Sale Price'), + ), + migrations.AlterField( + model_name='salesorderlineitem', + name='sale_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/order/migrations/0048_auto_20210702_2321.py b/InvenTree/order/migrations/0048_auto_20210702_2321.py new file mode 100644 index 0000000000..d6785e669e --- /dev/null +++ b/InvenTree/order/migrations/0048_auto_20210702_2321.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.4 on 2021-07-02 13:21 + +from django.db import migrations, models +import order.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0047_auto_20210701_0509'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorder', + name='reference', + field=models.CharField(default=order.models.get_next_po_number, help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'), + ), + migrations.AlterField( + model_name='salesorder', + name='reference', + field=models.CharField(default=order.models.get_next_so_number, help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'), + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index c150331f94..248ecb277d 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -17,24 +17,78 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils.translation import ugettext_lazy as _ -from common.settings import currency_code_default - from markdownx.models import MarkdownxField from mptt.models import TreeForeignKey -from djmoney.models.fields import MoneyField - from users import models as UserModels from part import models as PartModels from stock import models as stock_models from company.models import Company, SupplierPart -from InvenTree.fields import RoundingDecimalField +from InvenTree.fields import InvenTreeModelMoneyField, RoundingDecimalField from InvenTree.helpers import decimal2string, increment, getSetting from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus, StockHistoryCode from InvenTree.models import InvenTreeAttachment +def get_next_po_number(): + """ + Returns the next available PurchaseOrder reference number + """ + + if PurchaseOrder.objects.count() == 0: + return + + order = PurchaseOrder.objects.exclude(reference=None).last() + + attempts = set([order.reference]) + + reference = order.reference + + while 1: + reference = increment(reference) + + if reference in attempts: + # Escape infinite recursion + return reference + + if PurchaseOrder.objects.filter(reference=reference).exists(): + attempts.add(reference) + else: + break + + return reference + + +def get_next_so_number(): + """ + Returns the next available SalesOrder reference number + """ + + if SalesOrder.objects.count() == 0: + return + + order = SalesOrder.objects.exclude(reference=None).last() + + attempts = set([order.reference]) + + reference = order.reference + + while 1: + reference = increment(reference) + + if reference in attempts: + # Escape infinite recursion + return reference + + if SalesOrder.objects.filter(reference=reference).exists(): + attempts.add(reference) + else: + break + + return reference + + class Order(models.Model): """ Abstract model for an order. @@ -76,6 +130,8 @@ class Order(models.Model): while 1: new_ref = increment(ref) + print("Reference:", new_ref) + if new_ref in tries: # We are in a looping situation - simply return the original one return ref @@ -99,8 +155,6 @@ class Order(models.Model): class Meta: abstract = True - reference = models.CharField(unique=True, max_length=64, blank=False, verbose_name=_('Reference'), help_text=_('Order reference')) - description = models.CharField(max_length=250, verbose_name=_('Description'), help_text=_('Order description')) link = models.URLField(blank=True, verbose_name=_('Link'), help_text=_('Link to external page')) @@ -136,6 +190,10 @@ class PurchaseOrder(Order): target_date: Expected delivery target date for PurchaseOrder completion (optional) """ + @staticmethod + def get_api_url(): + return reverse('api-po-list') + OVERDUE_FILTER = Q(status__in=PurchaseOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date()) @staticmethod @@ -181,6 +239,15 @@ class PurchaseOrder(Order): return f"{prefix}{self.reference} - {self.supplier.name}" + reference = models.CharField( + unique=True, + max_length=64, + blank=False, + verbose_name=_('Reference'), + help_text=_('Order reference'), + default=get_next_po_number, + ) + status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(), help_text=_('Purchase order status')) @@ -407,6 +474,10 @@ class SalesOrder(Order): target_date: Target date for SalesOrder completion (optional) """ + @staticmethod + def get_api_url(): + return reverse('api-so-list') + OVERDUE_FILTER = Q(status__in=SalesOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date()) @staticmethod @@ -455,6 +526,15 @@ class SalesOrder(Order): def get_absolute_url(self): return reverse('so-detail', kwargs={'pk': self.id}) + reference = models.CharField( + unique=True, + max_length=64, + blank=False, + verbose_name=_('Reference'), + help_text=_('Order reference'), + default=get_next_so_number, + ) + customer = models.ForeignKey( Company, on_delete=models.SET_NULL, @@ -585,6 +665,10 @@ class PurchaseOrderAttachment(InvenTreeAttachment): Model for storing file attachments against a PurchaseOrder object """ + @staticmethod + def get_api_url(): + return reverse('api-po-attachment-list') + def getSubdir(self): return os.path.join("po_files", str(self.order.id)) @@ -596,6 +680,10 @@ class SalesOrderAttachment(InvenTreeAttachment): Model for storing file attachments against a SalesOrder object """ + @staticmethod + def get_api_url(): + return reverse('api-so-attachment-list') + def getSubdir(self): return os.path.join("so_files", str(self.order.id)) @@ -614,7 +702,13 @@ class OrderLineItem(models.Model): class Meta: abstract = True - quantity = RoundingDecimalField(max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], default=1, verbose_name=_('Quantity'), help_text=_('Item quantity')) + quantity = RoundingDecimalField( + verbose_name=_('Quantity'), + help_text=_('Item quantity'), + default=1, + max_digits=15, decimal_places=5, + validators=[MinValueValidator(0)], + ) reference = models.CharField(max_length=100, blank=True, verbose_name=_('Reference'), help_text=_('Line item reference')) @@ -629,6 +723,10 @@ class PurchaseOrderLineItem(OrderLineItem): """ + @staticmethod + def get_api_url(): + return reverse('api-po-line-list') + class Meta: unique_together = ( ('order', 'part') @@ -649,8 +747,15 @@ class PurchaseOrderLineItem(OrderLineItem): ) def get_base_part(self): - """ Return the base-part for the line item """ - return self.part.part + """ + Return the base part.Part object for the line item + + Note: Returns None if the SupplierPart is not set! + """ + if self.part is None: + return None + else: + return self.part.part # TODO - Function callback for when the SupplierPart is deleted? @@ -664,10 +769,9 @@ class PurchaseOrderLineItem(OrderLineItem): received = models.DecimalField(decimal_places=5, max_digits=15, default=0, verbose_name=_('Received'), help_text=_('Number of items received')) - purchase_price = MoneyField( + purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), null=True, blank=True, verbose_name=_('Purchase Price'), help_text=_('Unit purchase price'), @@ -712,14 +816,17 @@ class SalesOrderLineItem(OrderLineItem): sale_price: The unit sale price for this OrderLineItem """ + @staticmethod + def get_api_url(): + return reverse('api-so-line-list') + order = models.ForeignKey(SalesOrder, on_delete=models.CASCADE, related_name='lines', verbose_name=_('Order'), help_text=_('Sales Order')) part = models.ForeignKey('part.Part', on_delete=models.SET_NULL, related_name='sales_order_line_items', null=True, verbose_name=_('Part'), help_text=_('Part'), limit_choices_to={'salable': True}) - sale_price = MoneyField( + sale_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), null=True, blank=True, verbose_name=_('Sale Price'), help_text=_('Unit sale price'), @@ -774,6 +881,10 @@ class SalesOrderAllocation(models.Model): """ + @staticmethod + def get_api_url(): + return reverse('api-so-allocation-list') + class Meta: unique_together = [ # Cannot allocate any given StockItem to the same line more than once diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 821e8bf343..4a95bbb166 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -5,26 +5,29 @@ JSON serializers for the Order API # -*- coding: utf-8 -*- from __future__ import unicode_literals -from rest_framework import serializers - -from sql_util.utils import SubqueryCount +from django.utils.translation import ugettext_lazy as _ from django.db.models import Case, When, Value from django.db.models import BooleanField +from rest_framework import serializers +from sql_util.utils import SubqueryCount + from InvenTree.serializers import InvenTreeModelSerializer +from InvenTree.serializers import InvenTreeMoneySerializer from InvenTree.serializers import InvenTreeAttachmentSerializerField from company.serializers import CompanyBriefSerializer, SupplierPartSerializer from part.serializers import PartBriefSerializer -from stock.serializers import LocationBriefSerializer -from stock.serializers import StockItemSerializer, LocationSerializer +from stock.serializers import LocationBriefSerializer, StockItemSerializer, LocationSerializer from .models import PurchaseOrder, PurchaseOrderLineItem from .models import PurchaseOrderAttachment, SalesOrderAttachment from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation +from common.settings import currency_code_mappings + class POSerializer(InvenTreeModelSerializer): """ Serializer for a PurchaseOrder object """ @@ -70,6 +73,8 @@ class POSerializer(InvenTreeModelSerializer): overdue = serializers.BooleanField(required=False, read_only=True) + reference = serializers.CharField(required=True) + class Meta: model = PurchaseOrder @@ -83,6 +88,7 @@ class POSerializer(InvenTreeModelSerializer): 'link', 'overdue', 'reference', + 'responsible', 'supplier', 'supplier_detail', 'supplier_reference', @@ -119,9 +125,19 @@ class POLineItemSerializer(InvenTreeModelSerializer): part_detail = PartBriefSerializer(source='get_base_part', many=False, read_only=True) supplier_part_detail = SupplierPartSerializer(source='part', many=False, read_only=True) + purchase_price = InvenTreeMoneySerializer( + max_digits=19, decimal_places=4, + allow_null=True + ) + purchase_price_string = serializers.CharField(source='purchase_price', read_only=True) - destination = LocationBriefSerializer(source='get_destination', read_only=True) + destination_detail = LocationBriefSerializer(source='get_destination', read_only=True) + + purchase_price_currency = serializers.ChoiceField( + choices=currency_code_mappings(), + help_text=_('Purchase price currency'), + ) class Meta: model = PurchaseOrderLineItem @@ -140,6 +156,7 @@ class POLineItemSerializer(InvenTreeModelSerializer): 'purchase_price_currency', 'purchase_price_string', 'destination', + 'destination_detail', ] @@ -158,6 +175,11 @@ class POAttachmentSerializer(InvenTreeModelSerializer): 'order', 'attachment', 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] @@ -207,6 +229,8 @@ class SalesOrderSerializer(InvenTreeModelSerializer): overdue = serializers.BooleanField(required=False, read_only=True) + reference = serializers.CharField(required=True) + class Meta: model = SalesOrder @@ -222,6 +246,7 @@ class SalesOrderSerializer(InvenTreeModelSerializer): 'notes', 'overdue', 'reference', + 'responsible', 'status', 'status_text', 'shipment_date', @@ -317,13 +342,24 @@ class SOLineItemSerializer(InvenTreeModelSerializer): part_detail = PartBriefSerializer(source='part', many=False, read_only=True) allocations = SalesOrderAllocationSerializer(many=True, read_only=True) - # TODO: Once https://github.com/inventree/InvenTree/issues/1687 is fixed, remove default values - quantity = serializers.FloatField(default=1) + quantity = serializers.FloatField() allocated = serializers.FloatField(source='allocated_quantity', read_only=True) fulfilled = serializers.FloatField(source='fulfilled_quantity', read_only=True) + + sale_price = InvenTreeMoneySerializer( + max_digits=19, + decimal_places=4, + allow_null=True + ) + sale_price_string = serializers.CharField(source='sale_price', read_only=True) + sale_price_currency = serializers.ChoiceField( + choices=currency_code_mappings(), + help_text=_('Sale price currency'), + ) + class Meta: model = SalesOrderLineItem @@ -360,4 +396,9 @@ class SOAttachmentSerializer(InvenTreeModelSerializer): 'order', 'attachment', 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html index c7ba6be8a4..11396e07a7 100644 --- a/InvenTree/order/templates/order/order_base.html +++ b/InvenTree/order/templates/order/order_base.html @@ -145,10 +145,6 @@ src="{% static 'img/blank_image.png' %}" {% block js_ready %} {{ block.super }} -enableNavbar({ - label: 'po', - toggleId: '#po-menu-toggle', -}); {% if order.status == PurchaseOrderStatus.PENDING and order.lines.count > 0 %} $("#place-order").click(function() { @@ -164,11 +160,31 @@ $('#print-order-report').click(function() { }); $("#edit-order").click(function() { - launchModalForm("{% url 'po-edit' order.id %}", - { - reload: true, - } - ); + + constructForm('{% url "api-po-detail" order.pk %}', { + fields: { + reference: { + prefix: "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}", + }, + {% if order.lines.count == 0 and order.status == PurchaseOrderStatus.PENDING %} + supplier: { + }, + {% endif %} + supplier_reference: {}, + description: {}, + target_date: { + icon: 'fa-calendar-alt', + }, + link: { + icon: 'fa-link', + }, + responsible: { + icon: 'fa-user', + }, + }, + title: '{% trans "Edit Purchase Order" %}', + reload: true, + }); }); $("#receive-order").click(function() { diff --git a/InvenTree/order/templates/order/order_notes.html b/InvenTree/order/templates/order/order_notes.html deleted file mode 100644 index cdd121c412..0000000000 --- a/InvenTree/order/templates/order/order_notes.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "order/order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} -{% load markdownify %} - -{% block menubar %} -{% include 'order/po_navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Order Notes" %} -{% if roles.purchase_order.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} -
                - {% csrf_token %} - - {{ form }} -
                - -
                - -{{ form.media }} - -{% else %} - -
                -
                - {{ order.notes | markdownify }} -
                -
                -{% endif %} - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'po-notes' order.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/order_wizard/match_parts.html b/InvenTree/order/templates/order/order_wizard/match_parts.html index f97edff913..e0f030bad5 100644 --- a/InvenTree/order/templates/order/order_wizard/match_parts.html +++ b/InvenTree/order/templates/order/order_wizard/match_parts.html @@ -2,6 +2,7 @@ {% load inventree_extras %} {% load i18n %} {% load static %} +{% load crispy_forms_tags %} {% block form_alert %} {% if form.errors %} @@ -67,7 +68,7 @@ {% for field in form.visible_fields %} {% if field.name == row.quantity %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% if row.errors.quantity %} @@ -80,19 +81,19 @@ {% if item.column.guess == 'Purchase_Price' %} {% for field in form.visible_fields %} {% if field.name == row.purchase_price %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% elif item.column.guess == 'Reference' %} {% for field in form.visible_fields %} {% if field.name == row.reference %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% elif item.column.guess == 'Notes' %} {% for field in form.visible_fields %} {% if field.name == row.notes %} - {{ field }} + {{ field|as_crispy_field }} {% endif %} {% endfor %} {% else %} diff --git a/InvenTree/order/templates/order/order_wizard/po_upload.html b/InvenTree/order/templates/order/order_wizard/po_upload.html index a281725173..4357bce2c6 100644 --- a/InvenTree/order/templates/order/order_wizard/po_upload.html +++ b/InvenTree/order/templates/order/order_wizard/po_upload.html @@ -3,10 +3,6 @@ {% load i18n %} {% load static %} -{% block menubar %} -{% include 'order/po_navbar.html' with tab='upload' %} -{% endblock %} - {% block heading %} {% trans "Upload File for Purchase Order" %} {{ wizard.form.media }} diff --git a/InvenTree/order/templates/order/po_attachments.html b/InvenTree/order/templates/order/po_attachments.html deleted file mode 100644 index 40052c1ec6..0000000000 --- a/InvenTree/order/templates/order/po_attachments.html +++ /dev/null @@ -1,68 +0,0 @@ -{% extends "order/order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/po_navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Purchase Order Attachments" %} -{% endblock %} - -{% block details %} -{% include "attachment_table.html" with attachments=order.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - "{% url 'po-attachment-create' %}", - { - data: { - order: {{ order.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } -); - -$("#new-attachment").click(function() { - launchModalForm("{% url 'po-attachment-create' %}?order={{ order.id }}", - { - reload: true, - } - ); -}); - -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var url = `/order/purchase-order/attachment/${button.attr('pk')}/edit/`; - - launchModalForm(url, { - reload: true, - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var url = `/order/purchase-order/attachment/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({ -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/po_lineitem_delete.html b/InvenTree/order/templates/order/po_lineitem_delete.html deleted file mode 100644 index 1d9f80d137..0000000000 --- a/InvenTree/order/templates/order/po_lineitem_delete.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -{% trans "Are you sure you wish to delete this line item?" %} -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/po_navbar.html b/InvenTree/order/templates/order/po_navbar.html index 4dc501a8d6..9f7967810d 100644 --- a/InvenTree/order/templates/order/po_navbar.html +++ b/InvenTree/order/templates/order/po_navbar.html @@ -9,34 +9,34 @@
              • -
              • - - - {% trans "Details" %} +
              • + + + {% trans "Order Items" %}
              • {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} -
              • +
              • {% trans "Upload File" %}
              • {% endif %} -
              • - +
              • + {% trans "Received Items" %}
              • -
              • - +
              • + {% trans "Attachments" %}
              • -
              • - +
              • + {% trans "Notes" %} diff --git a/InvenTree/order/templates/order/po_received_items.html b/InvenTree/order/templates/order/po_received_items.html deleted file mode 100644 index 96dcb4fcf7..0000000000 --- a/InvenTree/order/templates/order/po_received_items.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "order/order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/po_navbar.html' with tab='received' %} -{% endblock %} - -{% block heading %} -{% trans "Received Items" %} -{% endblock %} - -{% block details %} - -{% include "stock_table.html" with read_only=True %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTable($("#stock-table"), { - params: { - purchase_order: {{ order.id }}, - part_detail: true, - supplier_detail: true, - location_detail: true, - }, - buttons: [ - '#stock-options', - ], - filterkey: "postock" -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 0ad73923a2..193fd75daa 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -4,30 +4,72 @@ {% load status_codes %} {% load i18n %} {% load static %} +{% load markdownify %} {% block menubar %} -{% include 'order/po_navbar.html' with tab='details' %} - +{% include 'order/po_navbar.html' %} {% endblock %} -{% block heading %} -{% trans "Purchase Order Items" %} -{% endblock %} +{% block page_content %} - -{% block details %} - - -
                - {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} - - {% endif %} +
                +
                +

                {% trans "Purchase Order Items" %}

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

                {% trans "Received Items" %}

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

                {% trans "Purchase Order Attachments" %}

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

                {% trans "Order Notes" %}

                +
                +
                +
                + +
                +
                +
                +
                +
                + {% if order.notes %} + {{ order.notes | markdownify }} + {% endif %} +
                +
                {% endblock %} @@ -35,28 +77,130 @@ {{ block.super }} -{% if order.status == PurchaseOrderStatus.PENDING %} -$('#new-po-line').click(function() { - launchModalForm("{% url 'po-line-item-create' %}", - { + enableNavbar({ + label: 'po', + toggleId: '#po-menu-toggle', + }); + + $('#edit-notes').click(function() { + constructForm('{% url "api-po-detail" order.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-po-attachment-list" %}', + { data: { order: {{ order.id }}, }, - secondary: [ - { - field: 'part', - label: '{% trans "New Supplier Part" %}', - title: '{% trans "Create new supplier part" %}', - url: "{% url 'supplier-part-create' %}", - data: { - supplier: {{ order.supplier.id }}, - }, - }, - ], + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } } ); + + loadAttachmentTable( + '{% url "api-po-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/po/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + + constructForm(`/api/order/po/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm('{% url "api-po-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true, + }, + }, + reload: true, + title: '{% trans "Add Attachment" %}', + }); + }); + + loadStockTable($("#stock-table"), { + params: { + purchase_order: {{ order.id }}, + part_detail: true, + supplier_part_detail: true, + location_detail: true, + }, + buttons: [ + '#stock-options', + ], + filterkey: "postock" + }); + +{% if order.status == PurchaseOrderStatus.PENDING %} +$('#new-po-line').click(function() { + + + constructForm('{% url "api-po-line-list" %}', { + fields: { + order: { + value: {{ order.pk }}, + hidden: true, + }, + part: { + filters: { + part_detail: true, + supplier_detail: true, + supplier: {{ order.supplier.pk }}, + }, + }, + quantity: {}, + reference: {}, + purchase_price: {}, + purchase_price_currency: { + {% if order.supplier.currency %} + value: '{{ order.supplier.currency }}', + {% endif %} + }, + destination: {}, + notes: {}, + }, + method: 'POST', + title: '{% trans "Add Line Item" %}', + onSuccess: reloadTable, + }); }); + {% endif %} function reloadTable() { @@ -72,16 +216,34 @@ function setupCallbacks() { table.find(".button-line-edit").click(function() { var pk = $(this).attr('pk'); - launchModalForm(`/order/purchase-order/line/${pk}/edit/`, { - success: reloadTable, + constructForm(`/api/order/po-line/${pk}/`, { + fields: { + part: { + filters: { + part_detail: true, + supplier_detail: true, + supplier: {{ order.supplier.pk }}, + } + }, + quantity: {}, + reference: {}, + purchase_price: {}, + purchase_price_currency: {}, + destination: {}, + notes: {}, + }, + title: '{% trans "Edit Line Item" %}', + onSuccess: reloadTable, }); }); table.find(".button-line-delete").click(function() { var pk = $(this).attr('pk'); - launchModalForm(`/order/purchase-order/line/${pk}/delete/`, { - success: reloadTable, + constructForm(`/api/order/po-line/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete Line Item" %}', + onSuccess: reloadTable, }); }); {% endif %} @@ -152,7 +314,11 @@ $("#po-table").inventreeTable({ field: 'supplier_part_detail.SKU', title: '{% trans "SKU" %}', formatter: function(value, row, index, field) { - return renderLink(value, `/supplier-part/${row.part}/`); + if (value) { + return renderLink(value, `/supplier-part/${row.part}/`); + } else { + return '-'; + } }, }, { @@ -161,10 +327,10 @@ $("#po-table").inventreeTable({ field: 'supplier_part_detail.MPN', title: '{% trans "MPN" %}', formatter: function(value, row, index, field) { - if (row.supplier_part_detail.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part.pk}/`); + if (row.supplier_part_detail && row.supplier_part_detail.manufacturer_part) { + return renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part}/`); } else { - return ""; + return "-"; } }, }, @@ -235,8 +401,15 @@ $("#po-table").inventreeTable({ } }, { - field: 'destination.pathstring', + field: 'destination', title: '{% trans "Destination" %}', + formatter: function(value, row) { + if (value) { + return renderLink(row.destination_detail.pathstring, `/stock/location/${value}/`); + } else { + return '-'; + } + } }, { field: 'notes', @@ -270,4 +443,9 @@ $("#po-table").inventreeTable({ ] }); + attachNavCallbacks({ + name: 'purchase-order', + default: 'order-items' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html index a2a5d5d0fa..de1c0dd8a9 100644 --- a/InvenTree/order/templates/order/purchase_orders.html +++ b/InvenTree/order/templates/order/purchase_orders.html @@ -176,19 +176,7 @@ $("#order-print").click(function() { }) $("#po-create").click(function() { - launchModalForm("{% url 'po-create' %}", - { - follow: true, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new Supplier" %}', - url: '{% url "supplier-create" %}', - } - ] - } - ); + createPurchaseOrder(); }); loadPurchaseOrderTable("#purchase-order-table", { diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index b342cefe66..60099a2578 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -153,7 +153,29 @@ enableNavbar({ }); $("#edit-order").click(function() { - launchModalForm("{% url 'so-edit' order.id %}", { + + constructForm('{% url "api-so-detail" order.pk %}', { + fields: { + reference: { + prefix: "{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}", + }, + {% if order.lines.count == 0 and order.status == SalesOrderStatus.PENDING %} + customer: { + }, + {% endif %} + customer_reference: {}, + description: {}, + target_date: { + icon: 'fa-calendar-alt', + }, + link: { + icon: 'fa-link', + }, + responsible: { + icon: 'fa-user', + }, + }, + title: '{% trans "Edit Sales Order" %}', reload: true, }); }); diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index b760409fe4..277c1f4278 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -4,47 +4,177 @@ {% load status_codes %} {% load i18n %} {% load static %} +{% load markdownify %} {% block menubar %} -{% include "order/so_navbar.html" with tab='details' %} +{% include "order/so_navbar.html" %} {% endblock %} -{% block heading %} -{% trans "Sales Order Items" %} -{% endblock %} +{% block page_content %} -{% block details %} - - -{% if roles.sales_order.change %} -
                - +
                +
                +

                {% trans "Sales Order Items" %}

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

                {% trans "Build Orders" %}

                +
                +
                +
                +
                +
                - +
                +
                +

                {% trans "Attachments" %}

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

                {% trans "Order Notes" %}

                +
                +
                +
                + +
                +
                +
                +
                +
                + {% if order.notes %} + {{ order.notes | markdownify }} + {% endif %} +
                +
                {% endblock %} {% block js_ready %} {{ block.super }} -function reloadTable() { - $("#so-lines-table").bootstrapTable("refresh"); -} + $('#edit-notes').click(function() { + constructForm('{% url "api-so-detail" order.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-so-attachment-list" %}', + { + data: { + order: {{ order.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + location.reload(); + } + } + ); + + loadAttachmentTable( + '{% url "api-so-attachment-list" %}', + { + filters: { + order: {{ order.pk }}, + }, + onEdit: function(pk) { + var url = `/api/order/so/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Edit Attachment" %}', + }); + }, + onDelete: function(pk) { + constructForm(`/api/order/so/attachment/${pk}/`, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm('{% url "api-so-attachment-list" %}', { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + order: { + value: {{ order.pk }}, + hidden: true + } + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}' + }); + }); + + loadBuildTable($("#builds-table"), { + url: "{% url 'api-build-list' %}", + params: { + sales_order: {{ order.id }}, + }, + }); + + function reloadTable() { + $("#so-lines-table").bootstrapTable("refresh"); + } $("#new-so-line").click(function() { - launchModalForm("{% url 'so-line-item-create' %}", { - success: reloadTable, - data: { - order: {{ order.id }}, + + constructForm('{% url "api-so-line-list" %}', { + fields: { + order: { + value: {{ order.pk }}, + hidden: true, + }, + part: {}, + quantity: {}, + reference: {}, + sale_price: {}, + sale_price_currency: {}, + notes: {}, }, - secondary: [ - ] + method: 'POST', + title: '{% trans "Add Line Item" %}', + onSuccess: reloadTable, }); }); @@ -377,16 +507,26 @@ function setupCallbacks() { var pk = $(this).attr('pk'); - launchModalForm(`/order/sales-order/line/${pk}/edit/`, { - success: reloadTable, + constructForm(`/api/order/so-line/${pk}/`, { + fields: { + quantity: {}, + reference: {}, + sale_price: {}, + sale_price_currency: {}, + notes: {}, + }, + title: '{% trans "Edit Line Item" %}', + onSuccess: reloadTable, }); }); table.find(".button-delete").click(function() { var pk = $(this).attr('pk'); - launchModalForm(`/order/sales-order/line/${pk}/delete/`, { - success: reloadTable, + constructForm(`/api/order/so-line/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete Line Item" %}', + onSuccess: reloadTable, }); }); @@ -473,6 +613,11 @@ function setupCallbacks() { } ); }); + + attachNavCallbacks({ + name: 'sales-order', + default: 'order-items' + }); } {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/sales_order_notes.html b/InvenTree/order/templates/order/sales_order_notes.html deleted file mode 100644 index 0a2e105b2e..0000000000 --- a/InvenTree/order/templates/order/sales_order_notes.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} -{% load markdownify %} -{% load status_codes %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Order Notes" %} -{% if roles.sales_order.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} - -
                - {% csrf_token %} - - {{ form }} -
                - -
                - -{{ form.media }} - -{% else %} -
                -
                - {{ order.notes | markdownify }} -
                -
                - -{% endif %} - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'so-notes' order.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/sales_orders.html b/InvenTree/order/templates/order/sales_orders.html index 448ab4b095..d4ebbd4ca8 100644 --- a/InvenTree/order/templates/order/sales_orders.html +++ b/InvenTree/order/templates/order/sales_orders.html @@ -178,19 +178,7 @@ $("#order-print").click(function() { }) $("#so-create").click(function() { - launchModalForm("{% url 'so-create' %}", - { - follow: true, - secondary: [ - { - field: 'customer', - label: '{% trans "New Customer" %}', - title: '{% trans "Create new Customer" %}', - url: '{% url "customer-create" %}', - } - ] - } - ); + createSalesOrder(); }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_attachments.html b/InvenTree/order/templates/order/so_attachments.html deleted file mode 100644 index b868aea48e..0000000000 --- a/InvenTree/order/templates/order/so_attachments.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Order Attachments" %} -{% endblock %} - -{% block details %} - -{% include "attachment_table.html" with attachments=order.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - "{% url 'so-attachment-create' %}", - { - data: { - order: {{ order.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } -); - -$("#new-attachment").click(function() { - launchModalForm("{% url 'so-attachment-create' %}?order={{ order.id }}", - { - reload: true, - } - ); -}); - -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var url = `/order/sales-order/attachment/${button.attr('pk')}/edit/`; - - launchModalForm(url, { - reload: true, - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var url = `/order/sales-order/attachment/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - reload: true, - }); -}); - -$("#attachment-table").inventreeTable({ -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_builds.html b/InvenTree/order/templates/order/so_builds.html deleted file mode 100644 index e29a76b64d..0000000000 --- a/InvenTree/order/templates/order/so_builds.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "order/sales_order_base.html" %} - -{% load inventree_extras %} -{% load i18n %} -{% load static %} - -{% block menubar %} -{% include 'order/so_navbar.html' with tab='builds' %} -{% endblock %} - -{% block heading %} -{% trans "Build Orders" %} -{% endblock %} - -{% block details %} - - -
                - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadBuildTable($("#builds-table"), { - url: "{% url 'api-build-list' %}", - params: { - sales_order: {{ order.id }}, - }, -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_lineitem_delete.html b/InvenTree/order/templates/order/so_lineitem_delete.html deleted file mode 100644 index 1d9f80d137..0000000000 --- a/InvenTree/order/templates/order/so_lineitem_delete.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -{% trans "Are you sure you wish to delete this line item?" %} -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/so_navbar.html b/InvenTree/order/templates/order/so_navbar.html index 4623febd02..710976ed3f 100644 --- a/InvenTree/order/templates/order/so_navbar.html +++ b/InvenTree/order/templates/order/so_navbar.html @@ -9,29 +9,29 @@
              • -
              • - - - {% trans "Details" %} +
              • + + + {% trans "Order Items" %}
              • -
              • - +
              • + {% trans "Build Orders" %}
              • -
              • - +
              • + {% trans "Attachments" %}
              • -
              • - +
              • + {% trans "Notes" %} diff --git a/InvenTree/order/test_views.py b/InvenTree/order/test_views.py index 23122d079d..4b49b6c94e 100644 --- a/InvenTree/order/test_views.py +++ b/InvenTree/order/test_views.py @@ -11,7 +11,6 @@ from django.contrib.auth.models import Group from InvenTree.status_codes import PurchaseOrderStatus from .models import PurchaseOrder, PurchaseOrderLineItem -from .models import SalesOrder import json @@ -60,88 +59,6 @@ class OrderListTest(OrderViewTestCase): self.assertEqual(response.status_code, 200) -class SalesOrderCreate(OrderViewTestCase): - """ - Create a SalesOrder using the form view - """ - - URL = reverse('so-create') - - def test_create_view(self): - """ - Retrieve the view for creating a sales order' - """ - - response = self.client.get(self.URL, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - self.assertEqual(response.status_code, 200) - - def post(self, data, **kwargs): - - return self.client.post(self.URL, data, HTTP_X_REQUESTED_WITH='XMLHttpRequest', **kwargs) - - def test_post_error(self): - """ - POST with errors - """ - - n = SalesOrder.objects.count() - - data = { - 'reference': '12345678', - } - - response = self.post(data) - - data = json.loads(response.content) - - self.assertIn('form_valid', data.keys()) - - # Customer is not specified - should return False - self.assertFalse(data['form_valid']) - - errors = json.loads(data['form_errors']) - - self.assertIn('customer', errors.keys()) - self.assertIn('description', errors.keys()) - - # No new SalesOrder objects should have been created - self.assertEqual(SalesOrder.objects.count(), n) - - def test_post_valid(self): - """ - POST a valid SalesOrder - """ - - n = SalesOrder.objects.count() - - data = { - 'reference': '12345678', - 'customer': 4, - 'description': 'A description', - } - - response = self.post(data) - - json_data = json.loads(response.content) - - self.assertTrue(json_data['form_valid']) - - # Create another SalesOrder, this time with a target date - data = { - 'reference': '12345679', - 'customer': 4, - 'description': 'Another order, this one with a target date!', - 'target_date': '2020-12-25', - } - - response = self.post(data) - - json_data = json.loads(response.content) - - self.assertEqual(SalesOrder.objects.count(), n + 2) - - class POTests(OrderViewTestCase): """ Tests for PurchaseOrder views """ @@ -152,28 +69,6 @@ class POTests(OrderViewTestCase): keys = response.context.keys() self.assertIn('PurchaseOrderStatus', keys) - def test_po_create(self): - """ Launch forms to create new PurchaseOrder""" - url = reverse('po-create') - - # Without a supplier ID - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # With a valid supplier ID - response = self.client.get(url, {'supplier': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # With an invalid supplier ID - response = self.client.get(url, {'supplier': 'goat'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - def test_po_edit(self): - """ Launch form to edit a PurchaseOrder """ - - response = self.client.get(reverse('po-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - def test_po_export(self): """ Export PurchaseOrder """ @@ -209,65 +104,6 @@ class POTests(OrderViewTestCase): order = PurchaseOrder.objects.get(pk=1) self.assertEqual(order.status, PurchaseOrderStatus.PLACED) - def test_line_item_create(self): - """ Test the form for adding a new LineItem to a PurchaseOrder """ - - # Record the number of line items in the PurchaseOrder - po = PurchaseOrder.objects.get(pk=1) - n = po.lines.count() - self.assertEqual(po.status, PurchaseOrderStatus.PENDING) - - url = reverse('po-line-item-create') - - # GET the form (pass the correct info) - response = self.client.get(url, {'order': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - post_data = { - 'part': 100, - 'quantity': 45, - 'reference': 'Test reference field', - 'notes': 'Test notes field' - } - - # POST with an invalid purchase order - post_data['order'] = 99 - response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - data = json.loads(response.content) - self.assertFalse(data['form_valid']) - - # POST with a part that does not match the purchase order - post_data['order'] = 1 - post_data['part'] = 7 - response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - data = json.loads(response.content) - self.assertFalse(data['form_valid']) - - # POST with an invalid part - post_data['part'] = 12345 - response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - data = json.loads(response.content) - self.assertFalse(data['form_valid']) - - # POST the form with valid data - post_data['part'] = 100 - response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - data = json.loads(response.content) - self.assertTrue(data['form_valid']) - - self.assertEqual(n + 1, PurchaseOrder.objects.get(pk=1).lines.count()) - - line = PurchaseOrderLineItem.objects.get(order=1, part=100) - self.assertEqual(line.quantity, 45) - - def test_line_item_edit(self): - """ Test editing form for PO line item """ - - url = reverse('po-line-item-edit', args=(22,)) - - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - class TestPOReceive(OrderViewTestCase): """ Tests for receiving a purchase order """ diff --git a/InvenTree/order/tests.py b/InvenTree/order/tests.py index 5452aec383..b68e0c3ff1 100644 --- a/InvenTree/order/tests.py +++ b/InvenTree/order/tests.py @@ -60,12 +60,6 @@ class OrderTest(TestCase): order.save() self.assertFalse(order.is_overdue) - def test_increment(self): - - next_ref = PurchaseOrder.getNextOrderNumber() - - self.assertEqual(next_ref, '0008') - def test_on_order(self): """ There should be 3 separate items on order for the M2x4 LPHS part """ diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 112a8cf297..2ce90f1f81 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -12,7 +12,6 @@ from . import views purchase_order_detail_urls = [ url(r'^cancel/', views.PurchaseOrderCancel.as_view(), name='po-cancel'), - url(r'^edit/', views.PurchaseOrderEdit.as_view(), name='po-edit'), url(r'^issue/', views.PurchaseOrderIssue.as_view(), name='po-issue'), url(r'^receive/', views.PurchaseOrderReceive.as_view(), name='po-receive'), url(r'^complete/', views.PurchaseOrderComplete.as_view(), name='po-complete'), @@ -20,66 +19,29 @@ purchase_order_detail_urls = [ url(r'^upload/', views.PurchaseOrderUpload.as_view(), name='po-upload'), url(r'^export/', views.PurchaseOrderExport.as_view(), name='po-export'), - url(r'^notes/', views.PurchaseOrderNotes.as_view(), name='po-notes'), - - url(r'^received/', views.PurchaseOrderDetail.as_view(template_name='order/po_received_items.html'), name='po-received'), - url(r'^attachments/', views.PurchaseOrderDetail.as_view(template_name='order/po_attachments.html'), name='po-attachments'), url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='po-detail'), ] purchase_order_urls = [ - url(r'^new/', views.PurchaseOrderCreate.as_view(), name='po-create'), - url(r'^order-parts/', views.OrderParts.as_view(), name='order-parts'), url(r'^pricing/', views.LineItemPricing.as_view(), name='line-pricing'), # Display detail view for a single purchase order url(r'^(?P\d+)/', include(purchase_order_detail_urls)), - url(r'^line/', include([ - url(r'^new/', views.POLineItemCreate.as_view(), name='po-line-item-create'), - url(r'^(?P\d+)/', include([ - url(r'^edit/', views.POLineItemEdit.as_view(), name='po-line-item-edit'), - url(r'^delete/', views.POLineItemDelete.as_view(), name='po-line-item-delete'), - ])), - ])), - - url(r'^attachment/', include([ - url(r'^new/', views.PurchaseOrderAttachmentCreate.as_view(), name='po-attachment-create'), - url(r'^(?P\d+)/edit/', views.PurchaseOrderAttachmentEdit.as_view(), name='po-attachment-edit'), - url(r'^(?P\d+)/delete/', views.PurchaseOrderAttachmentDelete.as_view(), name='po-attachment-delete'), - ])), - # Display complete list of purchase orders url(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'), ] sales_order_detail_urls = [ - - url(r'^edit/', views.SalesOrderEdit.as_view(), name='so-edit'), url(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'), url(r'^ship/', views.SalesOrderShip.as_view(), name='so-ship'), - url(r'^builds/', views.SalesOrderDetail.as_view(template_name='order/so_builds.html'), name='so-builds'), - url(r'^attachments/', views.SalesOrderDetail.as_view(template_name='order/so_attachments.html'), name='so-attachments'), - url(r'^notes/', views.SalesOrderNotes.as_view(), name='so-notes'), - url(r'^.*$', views.SalesOrderDetail.as_view(), name='so-detail'), ] sales_order_urls = [ - - url(r'^new/', views.SalesOrderCreate.as_view(), name='so-create'), - - url(r'^line/', include([ - url(r'^new/', views.SOLineItemCreate.as_view(), name='so-line-item-create'), - url(r'^(?P\d+)/', include([ - url(r'^edit/', views.SOLineItemEdit.as_view(), name='so-line-item-edit'), - url(r'^delete/', views.SOLineItemDelete.as_view(), name='so-line-item-delete'), - ])), - ])), - # URLs for sales order allocations url(r'^allocation/', include([ url(r'^new/', views.SalesOrderAllocationCreate.as_view(), name='so-allocation-create'), @@ -90,12 +52,6 @@ sales_order_urls = [ ])), ])), - url(r'^attachment/', include([ - url(r'^new/', views.SalesOrderAttachmentCreate.as_view(), name='so-attachment-create'), - url(r'^(?P\d+)/edit/', views.SalesOrderAttachmentEdit.as_view(), name='so-attachment-edit'), - url(r'^(?P\d+)/delete/', views.SalesOrderAttachmentDelete.as_view(), name='so-attachment-delete'), - ])), - # Display detail view for a single SalesOrder url(r'^(?P\d+)/', include(sales_order_detail_urls)), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 4a8e576a6d..be1107f17b 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -13,15 +13,15 @@ from django.core.exceptions import ValidationError from django.urls import reverse from django.http import HttpResponseRedirect from django.utils.translation import ugettext_lazy as _ -from django.views.generic import DetailView, ListView, UpdateView +from django.views.generic import DetailView, ListView from django.views.generic.edit import FormMixin from django.forms import HiddenInput, IntegerField import logging from decimal import Decimal, InvalidOperation -from .models import PurchaseOrder, PurchaseOrderLineItem, PurchaseOrderAttachment -from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment +from .models import PurchaseOrder, PurchaseOrderLineItem +from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation from .admin import POLineItemResource from build.models import Build @@ -30,7 +30,9 @@ from stock.models import StockItem, StockLocation from part.models import Part from common.models import InvenTreeSetting +from common.forms import UploadFileForm, MatchFieldForm from common.views import FileManagementFormView +from common.files import FileManager from . import forms as order_forms from part.views import PartPricing @@ -40,7 +42,8 @@ from InvenTree.helpers import DownloadFile, str2bool from InvenTree.helpers import extract_serial_numbers from InvenTree.views import InvenTreeRoleMixin -from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus +from InvenTree.status_codes import PurchaseOrderStatus, StockStatus + logger = logging.getLogger("inventree") @@ -94,322 +97,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class PurchaseOrderAttachmentCreate(AjaxCreateView): - """ - View for creating a new PurchaseOrderAttachment - """ - - model = PurchaseOrderAttachment - form_class = order_forms.EditPurchaseOrderAttachmentForm - ajax_form_title = _("Add Purchase Order Attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - "success": _("Added attachment") - } - - def get_initial(self): - """ - Get initial data for creating a new PurchaseOrderAttachment object. - - - Client must request this form with a parent PurchaseOrder in midn. - - e.g. ?order= - """ - - initials = super(AjaxCreateView, self).get_initial() - - try: - initials["order"] = PurchaseOrder.objects.get(id=self.request.GET.get('order', -1)) - except (ValueError, PurchaseOrder.DoesNotExist): - pass - - return initials - - def get_form(self): - """ - Create a form to upload a new PurchaseOrderAttachment - - - Hide the 'order' field - """ - - form = super(AjaxCreateView, self).get_form() - - form.fields['order'].widget = HiddenInput() - - return form - - -class SalesOrderAttachmentCreate(AjaxCreateView): - """ View for creating a new SalesOrderAttachment """ - - model = SalesOrderAttachment - form_class = order_forms.EditSalesOrderAttachmentForm - ajax_form_title = _('Add Sales Order Attachment') - - def save(self, form, **kwargs): - """ - Save the user that uploaded the attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - initials = super().get_initial().copy() - - try: - initials['order'] = SalesOrder.objects.get(id=self.request.GET.get('order', None)) - except (ValueError, SalesOrder.DoesNotExist): - pass - - return initials - - def get_form(self): - """ Hide the 'order' field """ - - form = super().get_form() - form.fields['order'].widget = HiddenInput() - - return form - - -class PurchaseOrderAttachmentEdit(AjaxUpdateView): - """ View for editing a PurchaseOrderAttachment object """ - - model = PurchaseOrderAttachment - form_class = order_forms.EditPurchaseOrderAttachmentForm - ajax_form_title = _("Edit Attachment") - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - def get_form(self): - form = super(AjaxUpdateView, self).get_form() - - # Hide the 'order' field - form.fields['order'].widget = HiddenInput() - - return form - - -class SalesOrderAttachmentEdit(AjaxUpdateView): - """ View for editing a SalesOrderAttachment object """ - - model = SalesOrderAttachment - form_class = order_forms.EditSalesOrderAttachmentForm - ajax_form_title = _("Edit Attachment") - - def get_data(self): - return { - 'success': _('Attachment updated') - } - - def get_form(self): - form = super().get_form() - - form.fields['order'].widget = HiddenInput() - - return form - - -class PurchaseOrderAttachmentDelete(AjaxDeleteView): - """ View for deleting a PurchaseOrderAttachment """ - - model = PurchaseOrderAttachment - ajax_form_title = _("Delete Attachment") - ajax_template_name = "order/delete_attachment.html" - context_object_name = "attachment" - - def get_data(self): - return { - "danger": _("Deleted attachment") - } - - -class SalesOrderAttachmentDelete(AjaxDeleteView): - """ View for deleting a SalesOrderAttachment """ - - model = SalesOrderAttachment - ajax_form_title = _("Delete Attachment") - ajax_template_name = "order/delete_attachment.html" - context_object_name = "attachment" - - def get_data(self): - return { - "danger": _("Deleted attachment") - } - - -class PurchaseOrderNotes(InvenTreeRoleMixin, UpdateView): - """ View for updating the 'notes' field of a PurchaseOrder """ - - context_object_name = 'order' - template_name = 'order/order_notes.html' - model = PurchaseOrder - - # Override the default permission roles - role_required = 'purchase_order.view' - - fields = ['notes'] - - def get_success_url(self): - - return reverse('po-notes', kwargs={'pk': self.get_object().id}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', False)) - - return ctx - - -class SalesOrderNotes(InvenTreeRoleMixin, UpdateView): - """ View for editing the 'notes' field of a SalesORder """ - - context_object_name = 'order' - template_name = 'order/sales_order_notes.html' - model = SalesOrder - role_required = 'sales_order.view' - - fields = ['notes'] - - def get_success_url(self): - return reverse('so-notes', kwargs={'pk': self.get_object().pk}) - - def get_context_data(self, **kwargs): - - ctx = super().get_context_data(**kwargs) - - ctx['editing'] = str2bool(self.request.GET.get('edit', False)) - - return ctx - - -class PurchaseOrderCreate(AjaxCreateView): - """ - View for creating a new PurchaseOrder object using a modal form - """ - - model = PurchaseOrder - ajax_form_title = _("Create Purchase Order") - form_class = order_forms.EditPurchaseOrderForm - - def get_initial(self): - initials = super().get_initial().copy() - - initials['reference'] = PurchaseOrder.getNextOrderNumber() - initials['status'] = PurchaseOrderStatus.PENDING - - supplier_id = self.request.GET.get('supplier', None) - - if supplier_id: - try: - supplier = Company.objects.get(id=supplier_id) - initials['supplier'] = supplier - except (Company.DoesNotExist, ValueError): - pass - - return initials - - def save(self, form, **kwargs): - """ - Record the user who created this PurchaseOrder - """ - - order = form.save(commit=False) - order.created_by = self.request.user - - return super().save(form) - - -class SalesOrderCreate(AjaxCreateView): - """ View for creating a new SalesOrder object """ - - model = SalesOrder - ajax_form_title = _("Create Sales Order") - form_class = order_forms.EditSalesOrderForm - - def get_initial(self): - initials = super().get_initial().copy() - - initials['reference'] = SalesOrder.getNextOrderNumber() - initials['status'] = SalesOrderStatus.PENDING - - customer_id = self.request.GET.get('customer', None) - - if customer_id is not None: - try: - customer = Company.objects.get(id=customer_id) - initials['customer'] = customer - except (Company.DoesNotExist, ValueError): - pass - - return initials - - def save(self, form, **kwargs): - """ - Record the user who created this SalesOrder - """ - - order = form.save(commit=False) - order.created_by = self.request.user - - return super().save(form) - - -class PurchaseOrderEdit(AjaxUpdateView): - """ View for editing a PurchaseOrder using a modal form """ - - model = PurchaseOrder - ajax_form_title = _('Edit Purchase Order') - form_class = order_forms.EditPurchaseOrderForm - - def get_form(self): - - form = super(AjaxUpdateView, self).get_form() - - order = self.get_object() - - # Prevent user from editing supplier if there are already lines in the order - if order.lines.count() > 0 or not order.status == PurchaseOrderStatus.PENDING: - form.fields['supplier'].widget = HiddenInput() - - return form - - -class SalesOrderEdit(AjaxUpdateView): - """ View for editing a SalesOrder """ - - model = SalesOrder - ajax_form_title = _('Edit Sales Order') - form_class = order_forms.EditSalesOrderForm - - def get_form(self): - form = super().get_form() - - # Prevent user from editing customer - form.fields['customer'].widget = HiddenInput() - - return form - - class PurchaseOrderCancel(AjaxUpdateView): """ View for cancelling a purchase order """ @@ -572,7 +259,28 @@ class SalesOrderShip(AjaxUpdateView): class PurchaseOrderUpload(FileManagementFormView): ''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) ''' + class OrderFileManager(FileManager): + REQUIRED_HEADERS = [ + 'Quantity', + ] + + ITEM_MATCH_HEADERS = [ + 'Manufacturer_MPN', + 'Supplier_SKU', + ] + + OPTIONAL_HEADERS = [ + 'Purchase_Price', + 'Reference', + 'Notes', + ] + name = 'order' + form_list = [ + ('upload', UploadFileForm), + ('fields', MatchFieldForm), + ('items', order_forms.OrderMatchItemForm), + ] form_steps_template = [ 'order/order_wizard/po_upload.html', 'order/order_wizard/match_fields.html', @@ -583,7 +291,6 @@ class PurchaseOrderUpload(FileManagementFormView): _("Match Fields"), _("Match Supplier Parts"), ] - # Form field name: PurchaseOrderLineItem field form_field_map = { 'item_select': 'part', 'quantity': 'quantity', @@ -591,6 +298,7 @@ class PurchaseOrderUpload(FileManagementFormView): 'reference': 'reference', 'notes': 'notes', } + file_manager_class = OrderFileManager def get_order(self): """ Get order or return 404 """ @@ -598,6 +306,8 @@ class PurchaseOrderUpload(FileManagementFormView): return get_object_or_404(PurchaseOrder, pk=self.kwargs['pk']) def get_context_data(self, form, **kwargs): + """ Handle context data for order """ + context = super().get_context_data(form=form, **kwargs) order = self.get_order() @@ -708,26 +418,7 @@ class PurchaseOrderUpload(FileManagementFormView): """ Once all the data is in, process it to add PurchaseOrderLineItem instances to the order """ order = self.get_order() - - items = {} - - for form_key, form_value in self.get_all_cleaned_data().items(): - # Split key from row value - try: - (field, idx) = form_key.split('-') - except ValueError: - continue - - if idx not in items: - # Insert into items - items.update({ - idx: { - self.form_field_map[field]: form_value, - } - }) - else: - # Update items - items[idx][self.form_field_map[field]] = form_value + items = self.get_clean_items() # Create PurchaseOrderLineItem instances for purchase_order_item in items.values(): @@ -1311,214 +1002,6 @@ class OrderParts(AjaxView): order.add_line_item(supplier_part, quantity, purchase_price=purchase_price) -class POLineItemCreate(AjaxCreateView): - """ AJAX view for creating a new PurchaseOrderLineItem object - """ - - model = PurchaseOrderLineItem - context_object_name = 'line' - form_class = order_forms.EditPurchaseOrderLineItemForm - ajax_form_title = _('Add Line Item') - - def validate(self, item, form, **kwargs): - - order = form.cleaned_data.get('order', None) - - part = form.cleaned_data.get('part', None) - - if not part: - form.add_error('part', _('Supplier part must be specified')) - - if part and order: - if not part.supplier == order.supplier: - form.add_error( - 'part', - _('Supplier must match for Part and Order') - ) - - def get_form(self): - """ Limit choice options based on the selected order, etc - """ - - form = super().get_form() - - # Limit the available to orders to ones that are PENDING - query = form.fields['order'].queryset - query = query.filter(status=PurchaseOrderStatus.PENDING) - form.fields['order'].queryset = query - - order_id = form['order'].value() - - try: - order = PurchaseOrder.objects.get(id=order_id) - - query = form.fields['part'].queryset - - # Only allow parts from the selected supplier - query = query.filter(supplier=order.supplier.id) - - exclude = [] - - for line in order.lines.all(): - if line.part and line.part.id not in exclude: - exclude.append(line.part.id) - - # Remove parts that are already in the order - query = query.exclude(id__in=exclude) - - form.fields['part'].queryset = query - form.fields['order'].widget = HiddenInput() - except (ValueError, PurchaseOrder.DoesNotExist): - pass - - return form - - def get_initial(self): - """ Extract initial data for the line item. - - - The 'order' will be passed as a query parameter - - Use this to set the 'order' field and limit the options for 'part' - """ - - initials = super().get_initial().copy() - - order_id = self.request.GET.get('order', None) - - if order_id: - try: - order = PurchaseOrder.objects.get(id=order_id) - initials['order'] = order - - except (PurchaseOrder.DoesNotExist, ValueError): - pass - - return initials - - -class SOLineItemCreate(AjaxCreateView): - """ Ajax view for creating a new SalesOrderLineItem object """ - - model = SalesOrderLineItem - context_order_name = 'line' - form_class = order_forms.EditSalesOrderLineItemForm - ajax_form_title = _('Add Line Item') - - def get_form(self, *args, **kwargs): - - form = super().get_form(*args, **kwargs) - - # If the order is specified, hide the widget - order_id = form['order'].value() - - if SalesOrder.objects.filter(id=order_id).exists(): - form.fields['order'].widget = HiddenInput() - - return form - - def get_initial(self): - """ - Extract initial data for this line item: - - Options: - order: The SalesOrder object - part: The Part object - """ - - initials = super().get_initial().copy() - - order_id = self.request.GET.get('order', None) - part_id = self.request.GET.get('part', None) - - if order_id: - try: - order = SalesOrder.objects.get(id=order_id) - initials['order'] = order - except (SalesOrder.DoesNotExist, ValueError): - pass - - if part_id: - try: - part = Part.objects.get(id=part_id) - if part.salable: - initials['part'] = part - except (Part.DoesNotExist, ValueError): - pass - - return initials - - def save(self, form): - ret = form.save() - # check if price s set in form - else autoset - if not ret.sale_price: - price = ret.part.get_price(ret.quantity) - # only if price is avail - if price: - ret.sale_price = price / ret.quantity - ret.save() - self.object = ret - return ret - - -class SOLineItemEdit(AjaxUpdateView): - """ View for editing a SalesOrderLineItem """ - - model = SalesOrderLineItem - form_class = order_forms.EditSalesOrderLineItemForm - ajax_form_title = _('Edit Line Item') - - def get_form(self): - form = super().get_form() - - form.fields.pop('order') - form.fields.pop('part') - - return form - - -class POLineItemEdit(AjaxUpdateView): - """ View for editing a PurchaseOrderLineItem object in a modal form. - """ - - model = PurchaseOrderLineItem - form_class = order_forms.EditPurchaseOrderLineItemForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Line Item') - - def get_form(self): - form = super().get_form() - - # Prevent user from editing order once line item is assigned - form.fields['order'].widget = HiddenInput() - - return form - - -class POLineItemDelete(AjaxDeleteView): - """ View for deleting a PurchaseOrderLineItem object in a modal form - """ - - model = PurchaseOrderLineItem - ajax_form_title = _('Delete Line Item') - ajax_template_name = 'order/po_lineitem_delete.html' - - def get_data(self): - return { - 'danger': _('Deleted line item'), - } - - -class SOLineItemDelete(AjaxDeleteView): - - model = SalesOrderLineItem - ajax_form_title = _("Delete Line Item") - ajax_template_name = "order/so_lineitem_delete.html" - - def get_data(self): - return { - 'danger': _('Deleted line item'), - } - - class SalesOrderAssignSerials(AjaxView, FormMixin): """ View for assigning stock items to a sales order, diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 60cea121a7..3a5fee4e3d 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -5,7 +5,8 @@ Provides a JSON API for the Part app # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django_filters.rest_framework import DjangoFilterBackend +from django.conf.urls import url, include +from django.urls import reverse from django.http import JsonResponse from django.db.models import Q, F, Count, Min, Max, Avg from django.utils.translation import ugettext_lazy as _ @@ -15,12 +16,13 @@ from rest_framework.response import Response from rest_framework import filters, serializers from rest_framework import generics +from django_filters.rest_framework import DjangoFilterBackend +from django_filters import rest_framework as rest_filters + from djmoney.money import Money from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate -from django.conf.urls import url, include -from django.urls import reverse from .models import Part, PartCategory, BomItem from .models import PartParameter, PartParameterTemplate @@ -116,9 +118,17 @@ class CategoryList(generics.ListCreateAPIView): ordering_fields = [ 'name', + 'level', + 'tree_id', + 'lft', ] - ordering = 'name' + # Use hierarchical ordering by default + ordering = [ + 'tree_id', + 'lft', + 'name' + ] search_fields = [ 'name', @@ -127,7 +137,10 @@ class CategoryList(generics.ListCreateAPIView): class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): - """ API endpoint for detail view of a single PartCategory object """ + """ + API endpoint for detail view of a single PartCategory object + """ + serializer_class = part_serializers.CategorySerializer queryset = PartCategory.objects.all() @@ -229,6 +242,24 @@ class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] +class PartAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for PartAttachment model + """ + + queryset = PartAttachment.objects.all() + serializer_class = part_serializers.PartAttachmentSerializer + + +class PartTestTemplateDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for PartTestTemplate model + """ + + queryset = PartTestTemplate.objects.all() + serializer_class = part_serializers.PartTestTemplateSerializer + + class PartTestTemplateList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a PartTestTemplate. @@ -337,8 +368,9 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView): def get_serializer(self, *args, **kwargs): + # By default, include 'category_detail' information in the detail view try: - kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', False)) + kwargs['category_detail'] = str2bool(self.request.query_params.get('category_detail', True)) except AttributeError: pass @@ -383,8 +415,90 @@ class PartDetail(generics.RetrieveUpdateDestroyAPIView): return response +class PartFilter(rest_filters.FilterSet): + """ + Custom filters for the PartList endpoint. + Uses the django_filters extension framework + """ + + # Filter by parts which have (or not) an IPN value + has_ipn = rest_filters.BooleanFilter(label='Has IPN', method='filter_has_ipn') + + def filter_has_ipn(self, queryset, name, value): + + value = str2bool(value) + + if value: + queryset = queryset.exclude(IPN='') + else: + queryset = queryset.filter(IPN='') + + # Regex filter for name + name_regex = rest_filters.CharFilter(label='Filter by name (regex)', field_name='name', lookup_expr='iregex') + + # Exact match for IPN + IPN = rest_filters.CharFilter( + label='Filter by exact IPN (internal part number)', + field_name='IPN', + lookup_expr="iexact" + ) + + # Regex match for IPN + IPN_regex = rest_filters.CharFilter(label='Filter by regex on IPN (internal part number)', field_name='IPN', lookup_expr='iregex') + + # low_stock filter + low_stock = rest_filters.BooleanFilter(label='Low stock', method='filter_low_stock') + + def filter_low_stock(self, queryset, name, value): + """ + Filter by "low stock" status + """ + + value = str2bool(value) + + if value: + # Ignore any parts which do not have a specified 'minimum_stock' level + queryset = queryset.exclude(minimum_stock=0) + # Filter items which have an 'in_stock' level lower than 'minimum_stock' + queryset = queryset.filter(Q(in_stock__lt=F('minimum_stock'))) + else: + # Filter items which have an 'in_stock' level higher than 'minimum_stock' + queryset = queryset.filter(Q(in_stock__gte=F('minimum_stock'))) + + return queryset + + # has_stock filter + has_stock = rest_filters.BooleanFilter(label='Has stock', method='filter_has_stock') + + def filter_has_stock(self, queryset, name, value): + + value = str2bool(value) + + if value: + queryset = queryset.filter(Q(in_stock__gt=0)) + else: + queryset = queryset.filter(Q(in_stock__lte=0)) + + return queryset + + is_template = rest_filters.BooleanFilter() + + assembly = rest_filters.BooleanFilter() + + component = rest_filters.BooleanFilter() + + trackable = rest_filters.BooleanFilter() + + purchaseable = rest_filters.BooleanFilter() + + salable = rest_filters.BooleanFilter() + + active = rest_filters.BooleanFilter() + + class PartList(generics.ListCreateAPIView): - """ API endpoint for accessing a list of Part objects + """ + API endpoint for accessing a list of Part objects - GET: Return list of objects - POST: Create a new Part object @@ -405,8 +519,8 @@ class PartList(generics.ListCreateAPIView): """ serializer_class = part_serializers.PartSerializer - queryset = Part.objects.all() + filterset_class = PartFilter starred_parts = None @@ -447,7 +561,7 @@ class PartList(generics.ListCreateAPIView): # Do we wish to include PartCategory detail? if str2bool(request.query_params.get('category_detail', False)): - # Work out which part categorie we need to query + # Work out which part categories we need to query category_ids = set() for part in data: @@ -519,6 +633,10 @@ class PartList(generics.ListCreateAPIView): params = self.request.query_params + # Annotate calculated data to the queryset + # (This will be used for further filtering) + queryset = part_serializers.PartSerializer.annotate_queryset(queryset) + queryset = super().filter_queryset(queryset) # Filter by "uses" query - Limit to parts which use the provided part @@ -545,17 +663,6 @@ class PartList(generics.ListCreateAPIView): except (ValueError, Part.DoesNotExist): pass - # Filter by whether the part has an IPN (internal part number) defined - has_ipn = params.get('has_ipn', None) - - if has_ipn is not None: - has_ipn = str2bool(has_ipn) - - if has_ipn: - queryset = queryset.exclude(IPN='') - else: - queryset = queryset.filter(IPN='') - # Filter by whether the BOM has been validated (or not) bom_valid = params.get('bom_valid', None) @@ -621,35 +728,14 @@ class PartList(generics.ListCreateAPIView): except (ValueError, PartCategory.DoesNotExist): pass - # Annotate calculated data to the queryset - # (This will be used for further filtering) - queryset = part_serializers.PartSerializer.annotate_queryset(queryset) + # Filer by 'depleted_stock' status -> has no stock and stock items + depleted_stock = params.get('depleted_stock', None) - # Filter by whether the part has stock - has_stock = params.get("has_stock", None) + if depleted_stock is not None: + depleted_stock = str2bool(depleted_stock) - if has_stock is not None: - has_stock = str2bool(has_stock) - - if has_stock: - queryset = queryset.filter(Q(in_stock__gt=0)) - else: - queryset = queryset.filter(Q(in_stock__lte=0)) - - # If we are filtering by 'low_stock' status - low_stock = params.get('low_stock', None) - - if low_stock is not None: - low_stock = str2bool(low_stock) - - if low_stock: - # Ignore any parts which do not have a specified 'minimum_stock' level - queryset = queryset.exclude(minimum_stock=0) - # Filter items which have an 'in_stock' level lower than 'minimum_stock' - queryset = queryset.filter(Q(in_stock__lt=F('minimum_stock'))) - else: - # Filter items which have an 'in_stock' level higher than 'minimum_stock' - queryset = queryset.filter(Q(in_stock__gte=F('minimum_stock'))) + if depleted_stock: + queryset = queryset.filter(Q(in_stock=0) & ~Q(stock_item_count=0)) # Filter by "parts which need stock to complete build" stock_to_build = params.get('stock_to_build', None) @@ -691,14 +777,7 @@ class PartList(generics.ListCreateAPIView): ] filter_fields = [ - 'is_template', 'variant_of', - 'assembly', - 'component', - 'trackable', - 'purchaseable', - 'salable', - 'active', ] ordering_fields = [ @@ -770,14 +849,54 @@ class PartParameterDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = part_serializers.PartParameterSerializer +class BomFilter(rest_filters.FilterSet): + """ + Custom filters for the BOM list + """ + + # Boolean filters for BOM item + optional = rest_filters.BooleanFilter(label='BOM line is optional') + inherited = rest_filters.BooleanFilter(label='BOM line is inherited') + allow_variants = rest_filters.BooleanFilter(label='Variants are allowed') + + validated = rest_filters.BooleanFilter(label='BOM line has been validated', method='filter_validated') + + def filter_validated(self, queryset, name, value): + + # Work out which lines have actually been validated + pks = [] + + for bom_item in queryset.all(): + if bom_item.is_line_valid(): + pks.append(bom_item.pk) + + if str2bool(value): + queryset = queryset.filter(pk__in=pks) + else: + queryset = queryset.exclude(pk__in=pks) + + return queryset + + # Filters for linked 'part' + part_active = rest_filters.BooleanFilter(label='Master part is active', field_name='part__active') + part_trackable = rest_filters.BooleanFilter(label='Master part is trackable', field_name='part__trackable') + + # Filters for linked 'sub_part' + sub_part_trackable = rest_filters.BooleanFilter(label='Sub part is trackable', field_name='sub_part__trackable') + sub_part_assembly = rest_filters.BooleanFilter(label='Sub part is an assembly', field_name='sub_part__assembly') + + class BomList(generics.ListCreateAPIView): - """ API endpoint for accessing a list of BomItem objects. + """ + API endpoint for accessing a list of BomItem objects. - GET: Return list of BomItem objects - POST: Create a new BomItem object """ serializer_class = part_serializers.BomItemSerializer + queryset = BomItem.objects.all() + filterset_class = BomFilter def list(self, request, *args, **kwargs): @@ -824,30 +943,6 @@ class BomList(generics.ListCreateAPIView): params = self.request.query_params - # Filter by "optional" status? - optional = params.get('optional', None) - - if optional is not None: - optional = str2bool(optional) - - queryset = queryset.filter(optional=optional) - - # Filter by "inherited" status - inherited = params.get('inherited', None) - - if inherited is not None: - inherited = str2bool(inherited) - - queryset = queryset.filter(inherited=inherited) - - # Filter by "allow_variants" - variants = params.get("allow_variants", None) - - if variants is not None: - variants = str2bool(variants) - - queryset = queryset.filter(allow_variants=variants) - # Filter by part? part = params.get('part', None) @@ -870,45 +965,6 @@ class BomList(generics.ListCreateAPIView): except (ValueError, Part.DoesNotExist): pass - # Filter by "active" status of the part - part_active = params.get('part_active', None) - - if part_active is not None: - part_active = str2bool(part_active) - queryset = queryset.filter(part__active=part_active) - - # Filter by "trackable" status of the part - part_trackable = params.get('part_trackable', None) - - if part_trackable is not None: - part_trackable = str2bool(part_trackable) - queryset = queryset.filter(part__trackable=part_trackable) - - # Filter by "trackable" status of the sub-part - sub_part_trackable = params.get('sub_part_trackable', None) - - if sub_part_trackable is not None: - sub_part_trackable = str2bool(sub_part_trackable) - queryset = queryset.filter(sub_part__trackable=sub_part_trackable) - - # Filter by whether the BOM line has been validated - validated = params.get('validated', None) - - if validated is not None: - validated = str2bool(validated) - - # Work out which lines have actually been validated - pks = [] - - for bom_item in queryset.all(): - if bom_item.is_line_valid: - pks.append(bom_item.pk) - - if validated: - queryset = queryset.filter(pk__in=pks) - else: - queryset = queryset.exclude(pk__in=pks) - # Annotate with purchase prices queryset = queryset.annotate( purchase_price_min=Min('sub_part__stock_items__purchase_price'), @@ -1023,11 +1079,13 @@ part_api_urls = [ # Base URL for PartTestTemplate API endpoints url(r'^test-template/', include([ + url(r'^(?P\d+)/', PartTestTemplateDetail.as_view(), name='api-part-test-template-detail'), url(r'^$', PartTestTemplateList.as_view(), name='api-part-test-template-list'), ])), # Base URL for PartAttachment API endpoints url(r'^attachment/', include([ + url(r'^(?P\d+)/', PartAttachmentDetail.as_view(), name='api-part-attachment-detail'), url(r'^$', PartAttachmentList.as_view(), name='api-part-attachment-list'), ])), @@ -1043,10 +1101,10 @@ part_api_urls = [ # Base URL for PartParameter API endpoints url(r'^parameter/', include([ - url(r'^template/$', PartParameterTemplateList.as_view(), name='api-part-param-template-list'), + url(r'^template/$', PartParameterTemplateList.as_view(), name='api-part-parameter-template-list'), - url(r'^(?P\d+)/', PartParameterDetail.as_view(), name='api-part-param-detail'), - url(r'^.*$', PartParameterList.as_view(), name='api-part-param-list'), + url(r'^(?P\d+)/', PartParameterDetail.as_view(), name='api-part-parameter-detail'), + url(r'^.*$', PartParameterList.as_view(), name='api-part-parameter-list'), ])), url(r'^thumbs/', include([ @@ -1054,7 +1112,7 @@ part_api_urls = [ url(r'^(?P\d+)/?', PartThumbsUpdate.as_view(), name='api-part-thumbs-update'), ])), - url(r'^(?P\d+)/?', PartDetail.as_view(), name='api-part-detail'), + url(r'^(?P\d+)/', PartDetail.as_view(), name='api-part-detail'), url(r'^.*$', PartList.as_view(), name='api-part-list'), ] diff --git a/InvenTree/part/bom.py b/InvenTree/part/bom.py index 42f49f9dde..81a0a4eb00 100644 --- a/InvenTree/part/bom.py +++ b/InvenTree/part/bom.py @@ -3,14 +3,9 @@ Functionality for Bill of Material (BOM) management. Primarily BOM upload tools. """ -from rapidfuzz import fuzz -import tablib -import os - from collections import OrderedDict -from django.utils.translation import gettext_lazy as _ -from django.core.exceptions import ValidationError +from django.utils.translation import gettext as _ from InvenTree.helpers import DownloadFile, GetExportFormats @@ -145,11 +140,16 @@ def ExportBom(part, fmt='csv', cascade=False, max_levels=None, parameter_data=Fa stock_data = [] # Get part default location try: - stock_data.append(bom_item.sub_part.get_default_location().name) + loc = bom_item.sub_part.get_default_location() + + if loc is not None: + stock_data.append(str(loc.name)) + else: + stock_data.append('') except AttributeError: stock_data.append('') # Get part current stock - stock_data.append(bom_item.sub_part.available_stock) + stock_data.append(str(bom_item.sub_part.available_stock)) for s_idx, header in enumerate(stock_headers): try: @@ -323,177 +323,6 @@ def ExportBom(part, fmt='csv', cascade=False, max_levels=None, parameter_data=Fa data = dataset.export(fmt) - filename = '{n}_BOM.{fmt}'.format(n=part.full_name, fmt=fmt) + filename = f"{part.full_name}_BOM.{fmt}" return DownloadFile(data, filename) - - -class BomUploadManager: - """ Class for managing an uploaded BOM file """ - - # Fields which are absolutely necessary for valid upload - REQUIRED_HEADERS = [ - 'Quantity' - ] - - # Fields which are used for part matching (only one of them is needed) - PART_MATCH_HEADERS = [ - 'Part_Name', - 'Part_IPN', - 'Part_ID', - ] - - # Fields which would be helpful but are not required - OPTIONAL_HEADERS = [ - 'Reference', - 'Note', - 'Overage', - ] - - EDITABLE_HEADERS = [ - 'Reference', - 'Note', - 'Overage' - ] - - HEADERS = REQUIRED_HEADERS + PART_MATCH_HEADERS + OPTIONAL_HEADERS - - def __init__(self, bom_file): - """ Initialize the BomUpload class with a user-uploaded file object """ - - self.process(bom_file) - - def process(self, bom_file): - """ Process a BOM file """ - - self.data = None - - ext = os.path.splitext(bom_file.name)[-1].lower() - - if ext in ['.csv', '.tsv', ]: - # These file formats need string decoding - raw_data = bom_file.read().decode('utf-8') - elif ext in ['.xls', '.xlsx']: - raw_data = bom_file.read() - else: - raise ValidationError({'bom_file': _('Unsupported file format: {f}').format(f=ext)}) - - try: - self.data = tablib.Dataset().load(raw_data) - except tablib.UnsupportedFormat: - raise ValidationError({'bom_file': _('Error reading BOM file (invalid data)')}) - except tablib.core.InvalidDimensions: - raise ValidationError({'bom_file': _('Error reading BOM file (incorrect row size)')}) - - def guess_header(self, header, threshold=80): - """ Try to match a header (from the file) to a list of known headers - - Args: - header - Header name to look for - threshold - Match threshold for fuzzy search - """ - - # Try for an exact match - for h in self.HEADERS: - if h == header: - return h - - # Try for a case-insensitive match - for h in self.HEADERS: - if h.lower() == header.lower(): - return h - - # Try for a case-insensitive match with space replacement - for h in self.HEADERS: - if h.lower() == header.lower().replace(' ', '_'): - return h - - # Finally, look for a close match using fuzzy matching - matches = [] - - for h in self.HEADERS: - ratio = fuzz.partial_ratio(header, h) - if ratio > threshold: - matches.append({'header': h, 'match': ratio}) - - if len(matches) > 0: - matches = sorted(matches, key=lambda item: item['match'], reverse=True) - return matches[0]['header'] - - return None - - def columns(self): - """ Return a list of headers for the thingy """ - headers = [] - - for header in self.data.headers: - headers.append({ - 'name': header, - 'guess': self.guess_header(header) - }) - - return headers - - def col_count(self): - if self.data is None: - return 0 - - return len(self.data.headers) - - def row_count(self): - """ Return the number of rows in the file. """ - - if self.data is None: - return 0 - - return len(self.data) - - def rows(self): - """ Return a list of all rows """ - rows = [] - - for i in range(self.row_count()): - - data = [item for item in self.get_row_data(i)] - - # Is the row completely empty? Skip! - empty = True - - for idx, item in enumerate(data): - if len(str(item).strip()) > 0: - empty = False - - try: - # Excel import casts number-looking-items into floats, which is annoying - if item == int(item) and not str(item) == str(int(item)): - data[idx] = int(item) - except ValueError: - pass - - # Skip empty rows - if empty: - continue - - row = { - 'data': data, - 'index': i - } - - rows.append(row) - - return rows - - def get_row_data(self, index): - """ Retrieve row data at a particular index """ - if self.data is None or index >= len(self.data): - return None - - return self.data[index] - - def get_row_dict(self, index): - """ Retrieve a dict object representing the data row at a particular offset """ - - if self.data is None or index >= len(self.data): - return None - - return self.data.dict[index] diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index ec799bcf8d..9523550198 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -5,21 +5,22 @@ Django Forms for interacting with Part objects # -*- coding: utf-8 -*- from __future__ import unicode_literals -from InvenTree.forms import HelperForm -from InvenTree.helpers import GetExportFormats -from InvenTree.fields import RoundingDecimalFormField - -from mptt.fields import TreeNodeChoiceField from django import forms from django.utils.translation import ugettext_lazy as _ -import common.models +from mptt.fields import TreeNodeChoiceField -from .models import Part, PartCategory, PartAttachment, PartRelated +from InvenTree.forms import HelperForm +from InvenTree.helpers import GetExportFormats, clean_decimal +from InvenTree.fields import RoundingDecimalFormField + +import common.models +from common.forms import MatchItemForm + +from .models import Part, PartCategory, PartRelated from .models import BomItem from .models import PartParameterTemplate, PartParameter from .models import PartCategoryParameterTemplate -from .models import PartTestTemplate from .models import PartSellPriceBreak, PartInternalPriceBreak @@ -55,32 +56,6 @@ class PartImageDownloadForm(HelperForm): ] -class PartImageForm(HelperForm): - """ Form for uploading a Part image """ - - class Meta: - model = Part - fields = [ - 'image', - ] - - -class EditPartTestTemplateForm(HelperForm): - """ Class for creating / editing a PartTestTemplate object """ - - class Meta: - model = PartTestTemplate - - fields = [ - 'part', - 'test_name', - 'description', - 'required', - 'requires_value', - 'requires_attachment', - ] - - class BomExportForm(forms.Form): """ Simple form to let user set BOM export options, before exporting a BOM (bill of materials) file. @@ -159,16 +134,28 @@ class BomValidateForm(HelperForm): ] -class BomUploadSelectFile(HelperForm): - """ Form for importing a BOM. Provides a file input box for upload """ +class BomMatchItemForm(MatchItemForm): + """ Override MatchItemForm fields """ - bom_file = forms.FileField(label=_('BOM file'), required=True, help_text=_("Select BOM file to upload")) + def get_special_field(self, col_guess, row, file_manager): + """ Set special fields """ - class Meta: - model = Part - fields = [ - 'bom_file', - ] + # set quantity field + if 'quantity' in col_guess.lower(): + return forms.CharField( + required=False, + widget=forms.NumberInput(attrs={ + 'name': 'quantity' + str(row['index']), + 'class': 'numberinput', + 'type': 'number', + 'min': '0', + 'step': 'any', + 'value': clean_decimal(row.get('quantity', '')), + }) + ) + + # return default + return super().get_special_field(col_guess, row, file_manager) class CreatePartRelatedForm(HelperForm): @@ -185,18 +172,6 @@ class CreatePartRelatedForm(HelperForm): } -class EditPartAttachmentForm(HelperForm): - """ Form for editing a PartAttachment object """ - - class Meta: - model = PartAttachment - fields = [ - 'part', - 'attachment', - 'comment' - ] - - class SetPartCategoryForm(forms.Form): """ Form for setting the category of multiple Part objects """ @@ -242,6 +217,11 @@ class EditPartForm(HelperForm): label=_('Include parent categories parameter templates'), widget=forms.HiddenInput()) + initial_stock = forms.IntegerField(required=False, + initial=0, + label=_('Initial stock amount'), + help_text=_('Create stock for this part')) + class Meta: model = Part fields = [ @@ -263,6 +243,7 @@ class EditPartForm(HelperForm): 'default_expiry', 'units', 'minimum_stock', + 'initial_stock', 'component', 'assembly', 'is_template', diff --git a/InvenTree/part/migrations/0069_auto_20210701_0509.py b/InvenTree/part/migrations/0069_auto_20210701_0509.py new file mode 100644 index 0000000000..86d8d2d44c --- /dev/null +++ b/InvenTree/part/migrations/0069_auto_20210701_0509.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0068_part_unique_part'), + ] + + operations = [ + migrations.AlterField( + model_name='partinternalpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='partinternalpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + migrations.AlterField( + model_name='partsellpricebreak', + name='price', + field=InvenTree.fields.InvenTreeModelMoneyField(currency_choices=[], decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'), + ), + migrations.AlterField( + model_name='partsellpricebreak', + name='price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/part/migrations/0070_alter_part_variant_of.py b/InvenTree/part/migrations/0070_alter_part_variant_of.py new file mode 100644 index 0000000000..a2b2f7ec18 --- /dev/null +++ b/InvenTree/part/migrations/0070_alter_part_variant_of.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.4 on 2021-07-08 07:02 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0069_auto_20210701_0509'), + ] + + operations = [ + migrations.AlterField( + model_name='part', + name='variant_of', + field=models.ForeignKey(blank=True, help_text='Is this part a variant of another part?', limit_choices_to={'is_template': True}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='variants', to='part.part', verbose_name='Variant Of'), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index c38f39738a..72d388746b 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -30,7 +30,7 @@ from mptt.models import TreeForeignKey, MPTTModel from stdimage.models import StdImageField -from decimal import Decimal +from decimal import Decimal, InvalidOperation from datetime import datetime from rapidfuzz import fuzz import hashlib @@ -39,7 +39,7 @@ from InvenTree import helpers from InvenTree import validators from InvenTree.models import InvenTreeTree, InvenTreeAttachment from InvenTree.fields import InvenTreeURLField -from InvenTree.helpers import decimal2string, normalize +from InvenTree.helpers import decimal2string, normalize, decimal2money from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus @@ -75,6 +75,10 @@ class PartCategory(InvenTreeTree): default_keywords = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Default keywords'), help_text=_('Default keywords for parts in this category')) + @staticmethod + def get_api_url(): + return reverse('api-part-category-list') + def get_absolute_url(self): return reverse('category-detail', kwargs={'pk': self.id}) @@ -329,6 +333,11 @@ class Part(MPTTModel): # For legacy reasons the 'variant_of' field is used to indicate the MPTT parent parent_attr = 'variant_of' + @staticmethod + def get_api_url(): + + return reverse('api-part-list') + def get_context_data(self, request, **kwargs): """ Return some useful context data about this part for template rendering @@ -683,7 +692,6 @@ class Part(MPTTModel): null=True, blank=True, limit_choices_to={ 'is_template': True, - 'active': True, }, on_delete=models.SET_NULL, help_text=_('Is this part a variant of another part?'), @@ -1479,16 +1487,17 @@ class Part(MPTTModel): return True - def get_price_info(self, quantity=1, buy=True, bom=True): + def get_price_info(self, quantity=1, buy=True, bom=True, internal=False): """ Return a simplified pricing string for this part Args: quantity: Number of units to calculate price for buy: Include supplier pricing (default = True) bom: Include BOM pricing (default = True) + internal: Include internal pricing (default = False) """ - price_range = self.get_price_range(quantity, buy, bom) + price_range = self.get_price_range(quantity, buy, bom, internal) if price_range is None: return None @@ -1576,9 +1585,10 @@ class Part(MPTTModel): - Supplier price (if purchased from suppliers) - BOM price (if built from other parts) + - Internal price (if set for the part) Returns: - Minimum of the supplier price or BOM price. If no pricing available, returns None + Minimum of the supplier, BOM or internal price. If no pricing available, returns None """ # only get internal price if set and should be used @@ -1966,6 +1976,10 @@ class PartAttachment(InvenTreeAttachment): Model for storing file attachments against a Part object """ + @staticmethod + def get_api_url(): + return reverse('api-part-attachment-list') + def getSubdir(self): return os.path.join("part_files", str(self.part.id)) @@ -1977,6 +1991,10 @@ class PartSellPriceBreak(common.models.PriceBreak): """ Represents a price break for selling this part """ + + @staticmethod + def get_api_url(): + return reverse('api-part-sale-price-list') part = models.ForeignKey( Part, on_delete=models.CASCADE, @@ -1994,6 +2012,10 @@ class PartInternalPriceBreak(common.models.PriceBreak): Represents a price break for internally selling this part """ + @staticmethod + def get_api_url(): + return reverse('api-part-internal-price-list') + part = models.ForeignKey( Part, on_delete=models.CASCADE, related_name='internalpricebreaks', @@ -2038,6 +2060,10 @@ class PartTestTemplate(models.Model): run on the model (refer to the validate_unique function). """ + @staticmethod + def get_api_url(): + return reverse('api-part-test-template-list') + def save(self, *args, **kwargs): self.clean() @@ -2136,6 +2162,10 @@ class PartParameterTemplate(models.Model): units: The units of the Parameter [string] """ + @staticmethod + def get_api_url(): + return reverse('api-part-parameter-template-list') + def __str__(self): s = str(self.name) if self.units: @@ -2173,6 +2203,10 @@ class PartParameter(models.Model): data: The data (value) of the Parameter [string] """ + @staticmethod + def get_api_url(): + return reverse('api-part-parameter-list') + def __str__(self): # String representation of a PartParameter (used in the admin interface) return "{part} : {param} = {data}{units}".format( @@ -2264,6 +2298,10 @@ class BomItem(models.Model): allow_variants: Stock for part variants can be substituted for this BomItem """ + @staticmethod + def get_api_url(): + return reverse('api-bom-list') + def save(self, *args, **kwargs): self.clean() @@ -2380,6 +2418,15 @@ class BomItem(models.Model): - If the "sub_part" is trackable, then the "part" must be trackable too! """ + super().clean() + + try: + self.quantity = Decimal(self.quantity) + except InvalidOperation: + raise ValidationError({ + 'quantity': _('Must be a valid number') + }) + try: # Check for circular BOM references if self.sub_part: @@ -2412,7 +2459,7 @@ class BomItem(models.Model): return "{n} x {child} to make {parent}".format( parent=self.part.full_name, child=self.sub_part.full_name, - n=helpers.decimal2string(self.quantity)) + n=decimal2string(self.quantity)) def available_stock(self): """ @@ -2496,10 +2543,12 @@ class BomItem(models.Model): return required @property - def price_range(self): + def price_range(self, internal=False): """ Return the price-range for this BOM item. """ - prange = self.sub_part.get_price_range(self.quantity) + # get internal price setting + use_internal = common.models.InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False) + prange = self.sub_part.get_price_range(self.quantity, internal=use_internal and internal) if prange is None: return prange @@ -2507,11 +2556,11 @@ class BomItem(models.Model): pmin, pmax = prange if pmin == pmax: - return decimal2string(pmin) + return decimal2money(pmin) # Convert to better string representation - pmin = decimal2string(pmin) - pmax = decimal2string(pmax) + pmin = decimal2money(pmin) + pmax = decimal2money(pmax) return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax) diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 6c47f1310f..92dda58590 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -4,6 +4,7 @@ JSON serializers for Part app import imghdr from decimal import Decimal +from django.urls import reverse_lazy from django.db import models from django.db.models import Q from django.db.models.functions import Coalesce @@ -31,6 +32,8 @@ class CategorySerializer(InvenTreeModelSerializer): parts = serializers.IntegerField(source='item_count', read_only=True) + level = serializers.IntegerField(read_only=True) + class Meta: model = PartCategory fields = [ @@ -38,10 +41,12 @@ class CategorySerializer(InvenTreeModelSerializer): 'name', 'description', 'default_location', - 'pathstring', - 'url', + 'default_keywords', + 'level', 'parent', 'parts', + 'pathstring', + 'url', ] @@ -59,7 +64,12 @@ class PartAttachmentSerializer(InvenTreeModelSerializer): 'pk', 'part', 'attachment', - 'comment' + 'comment', + 'upload_date', + ] + + read_only_fields = [ + 'upload_date', ] @@ -187,6 +197,9 @@ class PartSerializer(InvenTreeModelSerializer): Used when displaying all details of a single component. """ + def get_api_url(self): + return reverse_lazy('api-part-list') + def __init__(self, *args, **kwargs): """ Custom initialization method for PartSerializer, @@ -326,9 +339,10 @@ class PartSerializer(InvenTreeModelSerializer): 'category', 'category_detail', 'component', - 'description', - 'default_location', 'default_expiry', + 'default_location', + 'default_supplier', + 'description', 'full_name', 'image', 'in_stock', @@ -377,7 +391,7 @@ class PartStarSerializer(InvenTreeModelSerializer): class BomItemSerializer(InvenTreeModelSerializer): """ Serializer for BomItem object """ - # price_range = serializers.CharField(read_only=True) + price_range = serializers.CharField(read_only=True) quantity = serializers.FloatField() @@ -492,24 +506,11 @@ class BomItemSerializer(InvenTreeModelSerializer): 'reference', 'sub_part', 'sub_part_detail', - # 'price_range', + 'price_range', 'validated', ] -class PartParameterSerializer(InvenTreeModelSerializer): - """ JSON serializers for the PartParameter model """ - - class Meta: - model = PartParameter - fields = [ - 'pk', - 'part', - 'template', - 'data' - ] - - class PartParameterTemplateSerializer(InvenTreeModelSerializer): """ JSON serializer for the PartParameterTemplate model """ @@ -522,6 +523,22 @@ class PartParameterTemplateSerializer(InvenTreeModelSerializer): ] +class PartParameterSerializer(InvenTreeModelSerializer): + """ JSON serializers for the PartParameter model """ + + template_detail = PartParameterTemplateSerializer(source='template', many=False, read_only=True) + + class Meta: + model = PartParameter + fields = [ + 'pk', + 'part', + 'template', + 'template_detail', + 'data' + ] + + class CategoryParameterTemplateSerializer(InvenTreeModelSerializer): """ Serializer for PartCategoryParameterTemplate """ diff --git a/InvenTree/part/templates/part/allocation.html b/InvenTree/part/templates/part/allocation.html deleted file mode 100644 index e78456ea3a..0000000000 --- a/InvenTree/part/templates/part/allocation.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "part/part_base.html" %} -{% load status_codes %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab="allocation" %} -{% endblock %} - -{% block heading %} -{% trans "Build Order Allocations" %} -{% endblock %} - -{% block details %} - -
                - -{% endblock %} - -{% block pre_content_panel %} - -
                -
                -

                {% trans "Sales Order Allocations" %}

                -
                - -
                -
                -
                -
                - -{% endblock %} - - -{% block js_ready %} -{{ block.super }} - - loadSalesOrderAllocationTable("#sales-order-table", { - params: { - part: {{ part.id }}, - } - }); - - loadBuildOrderAllocationTable("#build-order-table", { - params: { - part: {{ part.id }}, - } - }); - -{% endblock %} diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html deleted file mode 100644 index 93440e13ed..0000000000 --- a/InvenTree/part/templates/part/attachments.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Part Attachments" %} -{% endblock %} - -{% block details %} - -{% include "attachment_table.html" with attachments=part.part_attachments %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - enableDragAndDrop( - '#attachment-dropzone', - "{% url 'part-attachment-create' %}", - { - data: { - part: {{ part.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } - ); - - $("#new-attachment").click(function() { - launchModalForm("{% url 'part-attachment-create' %}?part={{ part.id }}", - { - reload: true, - }); - }); - - $("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var url = `/part/attachment/${button.attr('pk')}/edit/`; - - launchModalForm(url, - { - reload: true, - }); - }); - - $("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var url = `/part/attachment/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - success: function() { - location.reload(); - } - }); - }); - - $("#attachment-table").inventreeTable({ - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom-delete.html b/InvenTree/part/templates/part/bom-delete.html deleted file mode 100644 index c2db77c040..0000000000 --- a/InvenTree/part/templates/part/bom-delete.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} - -{% trans "Are you sure you want to delete this BOM item?" %} -
                -{% trans "Deleting this entry will remove the BOM row from the following part" %}: - -
                  -
                • - {{ item.part.full_name }} - {{ item.part.description }} -
                • -
                - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html index dc345f9737..4376c23ab9 100644 --- a/InvenTree/part/templates/part/bom.html +++ b/InvenTree/part/templates/part/bom.html @@ -1,16 +1,11 @@ -{% extends "part/part_base.html" %} -{% load static %} {% load i18n %} +{% load inventree_extras %} -{% block menubar %} -{% include 'part/navbar.html' with tab='bom' %} -{% endblock %} - -{% block heading %} -{% trans "Bill of Materials" %} -{% endblock %} - -{% block details %} +{% if roles.part.change != True and editing_enabled %} +
                + {% trans "You do not have permission to edit the BOM." %} +
                +{% else %} {% if part.bom_checked_date %} {% if part.is_bom_valid %}
                @@ -26,7 +21,7 @@
                {% endif %} -
                +
                {% if editing_enabled %}
                - +
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - // Load the BOM table data - loadBomTable($("#bom-table"), { - editable: {{ editing_enabled }}, - bom_url: "{% url 'api-bom-list' %}", - part_url: "{% url 'api-part-list' %}", - parent_id: {{ part.id }} , - sub_part_detail: true, - }); - - linkButtonsToSelection($("#bom-table"), - [ - "#bom-item-delete", - ] - ); - - {% if editing_enabled %} - $("#editing-finished").click(function() { - location.href = "{% url 'part-bom' part.id %}"; - }); - - $('#bom-item-delete').click(function() { - - // Get a list of the selected BOM items - var rows = $("#bom-table").bootstrapTable('getSelections'); - - // TODO - In the future, display (in the dialog) which items are going to be deleted - - showQuestionDialog( - '{% trans "Delete selected BOM items?" %}', - '{% trans "All selected BOM items will be deleted" %}', - { - accept: function() { - - // Keep track of each DELETE request - var requests = []; - - rows.forEach(function(row) { - requests.push( - inventreeDelete( - `/api/bom/${row.pk}/`, - ) - ); - }); - - // Wait for *all* the requests to complete - $.when.apply($, requests).then(function() { - $('#bom-table').bootstrapTable('refresh'); - }); - } - } - ); - }); - - $('#bom-upload').click(function() { - location.href = "{% url 'upload-bom' part.id %}"; - }); - - $('#bom-duplicate').click(function() { - launchModalForm( - "{% url 'duplicate-bom' part.id %}", - { - success: function() { - $('#bom-table').bootstrapTable('refresh'); - } - } - ); - }); - - $("#bom-item-new").click(function () { - launchModalForm( - "{% url 'bom-item-create' %}?parent={{ part.id }}", - { - success: function() { - $("#bom-table").bootstrapTable('refresh'); - }, - secondary: [ - { - field: 'sub_part', - label: '{% trans "New Part" %}', - title: '{% trans "Create New Part" %}', - url: "{% url 'part-create' %}", - }, - ] - } - ); - }); - - {% else %} - - $("#validate-bom").click(function() { - launchModalForm( - "{% url 'bom-validate' part.id %}", - { - reload: true, - } - ); - }); - - $("#edit-bom").click(function () { - location.href = "{% url 'part-bom' part.id %}?edit=1"; - }); - - $("#download-bom").click(function () { - launchModalForm("{% url 'bom-export' part.id %}", - { - success: function(response) { - location.href = response.url; - }, - } - ); - }); - - {% endif %} - - $("#print-bom-report").click(function() { - printBomReports([{{ part.pk }}]); - }); - -{% endblock %} +{% endif %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom_upload/match_fields.html b/InvenTree/part/templates/part/bom_upload/match_fields.html new file mode 100644 index 0000000000..d1f325aaee --- /dev/null +++ b/InvenTree/part/templates/part/bom_upload/match_fields.html @@ -0,0 +1,99 @@ +{% extends "part/bom_upload/upload_file.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if missing_columns and missing_columns|length > 0 %} + +{% endif %} +{% if duplicates and duplicates|length > 0 %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + {% trans "File Fields" %} + + {% for col in form %} + +
                + + {{ col.name }} + +
                + + {% endfor %} + + + + + {% trans "Match Fields" %} + + {% for col in form %} + + {{ col }} + {% for duplicate in duplicates %} + {% if duplicate == col.value %} + + {% endif %} + {% endfor %} + + {% endfor %} + + {% for row in rows %} + {% with forloop.counter as row_index %} + + + + + {{ row_index }} + {% for item in row.data %} + + + {{ item }} + + {% endfor %} + + {% endwith %} + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.fieldselect').select2({ + width: '100%', + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom_upload/match_parts.html b/InvenTree/part/templates/part/bom_upload/match_parts.html new file mode 100644 index 0000000000..078ae8122f --- /dev/null +++ b/InvenTree/part/templates/part/bom_upload/match_parts.html @@ -0,0 +1,127 @@ +{% extends "part/bom_upload/upload_file.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} +{% load crispy_forms_tags %} + +{% block form_alert %} +{% if form.errors %} +{% endif %} +{% if form_errors %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + + {% trans "Row" %} + {% trans "Select Part" %} + {% trans "Reference" %} + {% trans "Quantity" %} + {% for col in columns %} + {% if col.guess != 'Quantity' %} + + + + {% if col.guess %} + {{ col.guess }} + {% else %} + {{ col.name }} + {% endif %} + + {% endif %} + {% endfor %} + + + + {% comment %} Dummy row for javascript del_row method {% endcomment %} + {% for row in rows %} + + + + + + {% add row.index 1 %} + + + {% for field in form.visible_fields %} + {% if field.name == row.item_select %} + {{ field }} + {% endif %} + {% endfor %} + {% if row.errors.part %} +

                {{ row.errors.part }}

                + {% endif %} + + + {% for field in form.visible_fields %} + {% if field.name == row.reference %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% if row.errors.reference %} +

                {{ row.errors.reference }}

                + {% endif %} + + + {% for field in form.visible_fields %} + {% if field.name == row.quantity %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% if row.errors.quantity %} +

                {{ row.errors.quantity }}

                + {% endif %} + + {% for item in row.data %} + {% if item.column.guess != 'Quantity' %} + + {% if item.column.guess == 'Overage' %} + {% for field in form.visible_fields %} + {% if field.name == row.overage %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% elif item.column.guess == 'Note' %} + {% for field in form.visible_fields %} + {% if field.name == row.note %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% else %} + {{ item.cell }} + {% endif %} + + + {% endif %} + {% endfor %} + + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.bomselect').select2({ + dropdownAutoWidth: true, + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom_upload/select_fields.html b/InvenTree/part/templates/part/bom_upload/select_fields.html deleted file mode 100644 index e82223da88..0000000000 --- a/InvenTree/part/templates/part/bom_upload/select_fields.html +++ /dev/null @@ -1,94 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab='bom' %} -{% endblock %} - -{% block heading %} -{% trans "Upload Bill of Materials" %} -{% endblock %} - -{% block details %} - -

                {% trans "Step 2 - Select Fields" %}

                -
                - -{% if missing_columns and missing_columns|length > 0 %} - -{% endif %} - -
                - - {% csrf_token %} - - - - - - - - - {% for col in bom_columns %} - - {% endfor %} - - - - - - - {% for col in bom_columns %} - - {% endfor %} - - {% for row in bom_rows %} - - - - {% for item in row.data %} - - {% endfor %} - - {% endfor %} - -
                {% trans "File Fields" %} -
                - - {{ col.name }} - -
                -
                {% trans "Match Fields" %} - - {% if col.duplicate %} -

                {% trans "Duplicate column selection" %}

                - {% endif %} -
                - - {{ forloop.counter }} - - {{ item.cell }} -
                - -
                - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom_upload/select_parts.html b/InvenTree/part/templates/part/bom_upload/select_parts.html deleted file mode 100644 index 41530e3c55..0000000000 --- a/InvenTree/part/templates/part/bom_upload/select_parts.html +++ /dev/null @@ -1,121 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab="bom" %} -{% endblock %} - -{% block heading %} -{% trans "Upload Bill of Materials" %} -{% endblock %} - -{% block details %} - -

                {% trans "Step 3 - Select Parts" %}

                -
                - -{% if form_errors %} - -{% endif %} - -
                - - - - {% csrf_token %} - {% load crispy_forms_tags %} - - - - - - - - - - - {% for col in bom_columns %} - - {% endfor %} - - - - {% for row in bom_rows %} - - - - - - {% for item in row.data %} - - {% endfor %} - - {% endfor %} - -
                {% trans "Row" %}{% trans "Select Part" %} - - - {% if col.guess %} - {{ col.guess }} - {% else %} - {{ col.name }} - {% endif %} -
                - - {% add row.index 1 %} - - - {% if row.errors.part %} -

                {{ row.errors.part }}

                - {% endif %} -
                - {% if item.column.guess == 'Part' %} - {{ item.cell }} - {% if row.errors.part %} -

                {{ row.errors.part }}

                - {% endif %} - {% elif item.column.guess == 'Quantity' %} - - {% if row.errors.quantity %} -

                {{ row.errors.quantity }}

                - {% endif %} - {% elif item.column.guess == 'Reference' %} - - {% elif item.column.guess == 'Note' %} - - {% elif item.column.guess == 'Overage' %} - - {% else %} - {{ item.cell }} - {% endif %} - -
                - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -$('.bomselect').select2({ - dropdownAutoWidth: true, - matcher: partialMatcher, -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/bom_upload/upload_file.html b/InvenTree/part/templates/part/bom_upload/upload_file.html index 148d32f5da..e31cfbaf56 100644 --- a/InvenTree/part/templates/part/bom_upload/upload_file.html +++ b/InvenTree/part/templates/part/bom_upload/upload_file.html @@ -3,18 +3,15 @@ {% load i18n %} {% load inventree_extras %} -{% block menubar %} -{% include "part/navbar.html" with tab='bom' %} -{% endblock %} - {% block heading %} -{% trans "Upload Bill of Materials" %} +{% trans "Upload BOM File" %} {% endblock %} -{% block details %} +{% block page_content %} -

                {% trans "Step 1 - Select BOM File" %}

                +

                {% trans "Upload Bill of Materials" %}

                +{% block form_alert %}
                {% trans "Requirements for BOM upload" %}:
                  @@ -22,16 +19,31 @@
                • {% trans "Each part must already exist in the database" %}
                +{% endblock %} -
                - - {% csrf_token %} - {% load crispy_forms_tags %} +

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

                - + +{% csrf_token %} +{% load crispy_forms_tags %} - {% crispy form %} +{% block form_buttons_top %} +{% endblock form_buttons_top %} + +{{ wizard.management_form }} +{% block form_content %} +{% crispy wizard.form %} +{% endblock form_content %} +
                + +{% block form_buttons_bottom %} +{% if wizard.steps.prev %} + +{% endif %} +
                +{% endblock form_buttons_bottom %} {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/build.html b/InvenTree/part/templates/part/build.html deleted file mode 100644 index 4c28bef3d4..0000000000 --- a/InvenTree/part/templates/part/build.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='build' %} -{% endblock %} - -{% block heading %} -{% trans "Part Builds" %} -{% endblock %} - -{% block details %} -
                -
                - {% if part.active %} - {% if roles.build.add %} - - {% endif %} - {% endif %} -
                - -
                -
                -
                - - -
                - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - $("#start-build").click(function() { - newBuildOrder({ - data: { - part: {{ part.id }}, - } - }); - }); - - loadBuildTable($("#build-table"), { - url: "{% url 'api-build-list' %}", - params: { - part: {{ part.id }}, - } - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 44cbeac99f..0aee97a5e3 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -3,11 +3,20 @@ {% load i18n %} {% block menubar %} -{% include 'part/category_navbar.html' with tab='parts' %} +{% include 'part/category_navbar.html' %} {% endblock %} {% block content %} +{% if messages %} + {% for message in messages %} +
                + {{ message|safe }} +
                + {% endfor %} +{% endif %} + +
                @@ -106,63 +115,81 @@
                -{% block category_content %} +{% block page_content %} -
                -
                - - {% if roles.part.add %} - - {% endif %} +
                +
                +

                {% trans "Parts" %}

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

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

                +

                {% trans "Part Parameters" %}

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

                {% trans "Subcategories" %}

                +
                +
                +
                +
                + +
                + +
                +
                +
                + +
                +
                {% endblock %} - -{% block category_tables %} -{% endblock category_tables %} - {% endblock %} {% block js_load %} {{ block.super }} @@ -171,6 +198,26 @@ {% block js_ready %} {{ block.super }} + loadPartCategoryTable($('#subcategory-table'), { + params: { + {% if category %} + parent: {{ category.pk }} + {% else %} + parent: 'null' + {% endif %} + } + }); + + {% if category %} + loadParametricPartTable( + "#parametric-part-table", + { + headers: {{ headers|safe }}, + data: {{ parameters|safe }}, + } + ); + {% endif %} + enableNavbar({ label: 'category', toggleId: '#category-menu-toggle', @@ -197,11 +244,11 @@ "{% url 'category-create' %}", { follow: true, - {% if category %} data: { + {% if category %} category: {{ category.id }} + {% endif %} }, - {% endif %} secondary: [ { field: 'default_location', @@ -259,13 +306,25 @@ {% if category %} $("#cat-edit").click(function () { - launchModalForm( - "{% url 'category-edit' category.id %}", + + constructForm( + '{% url "api-part-category-detail" category.pk %}', { + fields: { + name: {}, + description: {}, + parent: { + help_text: '{% trans "Select parent category" %}', + }, + default_location: {}, + default_keywords: { + icon: 'fa-key', + } + }, + title: '{% trans "Edit Part Category" %}', reload: true - }, + } ); - return false; }); {% if category.parent %} @@ -307,4 +366,9 @@ $('#view-list').hide(); } + attachNavCallbacks({ + name: 'partcategory', + default: 'part-stock' + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_navbar.html b/InvenTree/part/templates/part/category_navbar.html index d84b49a311..aa3a491160 100644 --- a/InvenTree/part/templates/part/category_navbar.html +++ b/InvenTree/part/templates/part/category_navbar.html @@ -1,4 +1,7 @@ {% load i18n %} +{% load inventree_extras %} + +{% settings_value 'PART_SHOW_IMPORT' as show_import %}
                  @@ -8,31 +11,32 @@ -
                • - {% if category %} - - {% else %} - - {% endif %} +
                • + {% trans "Subcategories" %}
                • -
                • - {% if category %} - - {% else %} - - {% endif %} +
                • + {% trans "Parts" %}
                • + {% if show_import and user.is_staff and roles.part.add %} +
                • + + + {% trans "Import Parts" %} + +
                • + {% endif %} + {% if category %} -
                • - +
                • + {% trans "Parameters" %} diff --git a/InvenTree/part/templates/part/category_parametric.html b/InvenTree/part/templates/part/category_parametric.html deleted file mode 100644 index 881a292986..0000000000 --- a/InvenTree/part/templates/part/category_parametric.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "part/category.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='parameters' %} -{% endblock %} - -{% block heading %} -{% trans "Part Parameters" %} -{% endblock %} - -{% block details %} - - -
                  - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - /* Hide Button Toolbar */ - window.onload = function hideButtonToolbar() { - var toolbar = document.getElementById("button-toolbar"); - toolbar.style.display = "none"; - }; - - loadParametricPartTable( - "#parametric-part-table", - { - headers: {{ headers|safe }}, - data: {{ parameters|safe }}, - } - ); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/category_partlist.html b/InvenTree/part/templates/part/category_partlist.html deleted file mode 100644 index e78254c541..0000000000 --- a/InvenTree/part/templates/part/category_partlist.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "part/category.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='parts' %} -{% endblock %} - -{% block heading %} -{% trans "Parts" %} -{% endblock %} - -{% block details %} - -
                  -{% endblock %} diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index e077e5af01..b4cebe478e 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,238 +1,326 @@ {% extends "part/part_base.html" %} {% load static %} {% load i18n %} - +{% load inventree_extras %} +{% load crispy_forms_tags %} +{% load markdownify %} {% block menubar %} -{% include 'part/navbar.html' with tab='details' %} +{% include 'part/navbar.html' %} {% endblock %} -{% block heading %} -{% trans "Part Details" %} -{% endblock %} +{% block page_content %} -{% block details %} - -
                  -
                  - - - - - - - - {% if part.IPN %} - - - - - - {% endif %} - {% if part.revision %} - - - - - - {% endif %} - {% if part.trackable %} - - - - - - {% endif %} - - - - - - {% if part.variant_of %} - - - - - - {% endif %} - {% if part.keywords %} - - - - - - {% endif %} - - - - - - {% if part.link %} - - - - - - {% endif %} - {% if part.default_location %} - - - - - - {% endif %} - {% if part.default_supplier %} - - - - - - {% endif %} - {% if part.units %} - - - - - - {% endif %} - {% if part.minimum_stock > 0 %} - - - - - - {% endif %} - {% if part.default_expiry > 0 %} - - - - - - {% endif %} - - - - - - {% if part.creation_user %} - - - - - - {% endif %} - {% if part.responsible %} - - - - - - {% endif %} -
                  {% trans "Part name" %}{{ part.name }}{% include "clip.html"%}
                  {% trans "IPN" %}{{ part.IPN }}{% include "clip.html"%}
                  {% trans "Revision" %}{{ part.revision }}{% include "clip.html"%}
                  {% trans "Latest Serial Number" %} - {% if part.getLatestSerialNumber %} - {{ part.getLatestSerialNumber }}{% include "clip.html"%} - {% else %} - {% trans "No serial numbers recorded" %} - {% endif %} -
                  {% trans "Description" %}{{ part.description }}{% include "clip.html"%}
                  {% trans "Variant Of" %}{{ part.variant_of.full_name }}{% include "clip.html"%}
                  {% trans "Keywords" %}{{ part.keywords }}{% include "clip.html"%}
                  {% trans "Category" %} - {% if part.category %} - {{ part.category.pathstring }}{% include "clip.html"%} - {% endif %} -
                  {% trans "External Link" %}{{ part.link }}{% include "clip.html"%}
                  {% trans "Default Location" %}{{ part.default_location.pathstring }}{% include "clip.html"%}
                  {% trans "Default Supplier" %} - {{ part.default_supplier.supplier.name }} | {{ part.default_supplier.SKU }} - {% include "clip.html"%}
                  {% trans "Units" %}{{ part.units }}{% include "clip.html"%}
                  {% trans "Minimum Stock" %}{{ part.minimum_stock }}
                  {% trans "Stock Expiry Time" %}{{ part.default_expiry }} {% trans "days" %}
                  {% trans "Creation Date" %}{{ part.creation_date }}
                  {% trans "Created By" %}{{ part.creation_user }}
                  d{% trans "Responsible User" %}{{ part.responsible }}
                  +
                  +
                  +

                  {% trans "Part Stock" %}

                  -
                  - - - - - - - {% if part.virtual %} - - {% else %} - - {% endif %} - - - - - - {% if part.is_template %} - - {% else %} - - {% endif %} - - - - - - {% if part.assembly %} - - {% else %} - - {% endif %} - - - - - - {% if part.component %} - - {% else %} - - {% endif %} - - - - - - {% if part.trackable %} - - {% else %} - - {% endif %} - - - - - - {% if part.purchaseable %} - - {% else %} - - {% endif %} - - - - - - {% if part.salable %} - - {% else %} - - {% endif %} - - - - - - - {% if part.active %} - - {% else %} - - {% endif %} - -
                  {% trans "Virtual" %}{% include "slide.html" with state=part.virtual field='virtual' %}{% trans "Part is virtual (not a physical part)" %}{% trans "Part is not a virtual part" %}
                  {% trans "Template" %}{% include "slide.html" with state=part.is_template field='is_template' %}{% trans "Part is a template part (variants can be made from this part)" %}{% trans "Part is not a template part" %}
                  {% trans "Assembly" %}{% include "slide.html" with state=part.assembly field='assembly' %}{% trans "Part can be assembled from other parts" %}{% trans "Part cannot be assembled from other parts" %}
                  {% trans "Component" %}{% include "slide.html" with state=part.component field='component' %}{% trans "Part can be used in assemblies" %}{% trans "Part cannot be used in assemblies" %}
                  {% trans "Trackable" %}{% include "slide.html" with state=part.trackable field='trackable' %}{% trans "Part stock is tracked by serial number" %}{% trans "Part stock is not tracked by serial number" %}
                  {% trans "Purchaseable" %}{% include "slide.html" with state=part.purchaseable field='purchaseable' %}{% trans "Part can be purchased from external suppliers" %}{% trans "Part can be purchased from external suppliers" %}
                  {% trans "Salable" %}{% include "slide.html" with state=part.salable field='salable' %}{% trans "Part can be sold to customers" %}{% trans "Part cannot be sold to customers" %}
                  - {% if part.active %} - - {% else %} - +
                  + {% if part.is_template %} +
                  + {% blocktrans with full_name=part.full_name%}Showing stock for all variants of {{full_name}}{% endblocktrans %} +
                  + {% endif %} + {% include "stock_table.html" %} +
                  + + +
                  +
                  +

                  {% trans "Part Test Templates" %}

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

                  {% trans "Purchase Orders" %}

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

                  {% trans "Sales Orders" %}

                  +
                  +
                  +
                  +
                  + {% if 0 %} + {% endif %} -
                  {% trans "Active" %}{% include "slide.html" with state=part.active field='active' disabled=False %}{% trans "Part is active" %}{% trans "Part is not active" %}
                  +
                  + +
                  +
                  +
                  + + +
                  +
                  + +
                  +

                  {% trans "Sales Order Allocations" %}

                  +
                  +
                  +
                  +
                  +
                  + +
                  + {% include "part/prices.html" %} +
                  + +
                  +
                  +
                  +
                  +

                  {% trans "Notes" %}

                  +
                  +
                  +
                  + +
                  +
                  +
                  +
                  +
                  + {% if part.notes %} + {{ part.notes | markdownify }} + {% endif %} +
                  +
                  + +
                  + +
                  + +
                  +
                  +

                  {% trans "Part Variants" %}

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

                  {% trans "Parameters" %}

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

                  {% trans "Attachments" %}

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

                  {% trans "Bill of Materials" %}

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

                  {% trans "Assemblies" %}

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

                  {% trans "Part Builds" %}

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

                  {% trans "Build Order Allocations" %}

                  +
                  +
                  +
                  +
                  +
                  + +
                  +
                  +

                  {% trans "Part Suppliers" %}

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

                  {% trans "Part Manufacturers" %}

                  +
                  +
                  +
                  +
                  +
                  + +
                  + + +
                  +
                  +
                  +
                  +
                  @@ -245,6 +333,344 @@ {% block js_ready %} {{ block.super }} + enableNavbar({ + label: 'part', + toggleId: '#part-menu-toggle', + }); + + + loadBuildOrderAllocationTable("#build-order-allocation-table", { + params: { + part: {{ part.id }}, + } + }); + + loadSalesOrderAllocationTable("#sales-order-allocation-table", { + params: { + part: {{ part.id }}, + } + }); + + loadPartTable('#used-table', + '{% url "api-part-list" %}', + { + params: { + uses: {{ part.pk }}, + }, + filterTarget: '#filter-list-usedin', + } + ); + + // Load the BOM table data + loadBomTable($("#bom-table"), { + editable: {{ editing_enabled }}, + bom_url: "{% url 'api-bom-list' %}", + part_url: "{% url 'api-part-list' %}", + parent_id: {{ part.id }} , + sub_part_detail: true, + }); + + // Load the BOM table data in the pricing view + loadBomTable($("#bom-pricing-table"), { + editable: {{ editing_enabled }}, + bom_url: "{% url 'api-bom-list' %}", + part_url: "{% url 'api-part-list' %}", + parent_id: {{ part.id }} , + sub_part_detail: true, + }); + + + linkButtonsToSelection($("#bom-table"), + [ + "#bom-item-delete", + ] + ); + + {% if editing_enabled %} + $("#editing-finished").click(function() { + location.href = "{% url 'part-detail' part.id %}?display=bom"; + }); + + $('#bom-item-delete').click(function() { + + // Get a list of the selected BOM items + var rows = $("#bom-table").bootstrapTable('getSelections'); + + // TODO - In the future, display (in the dialog) which items are going to be deleted + + showQuestionDialog( + '{% trans "Delete selected BOM items?" %}', + '{% trans "All selected BOM items will be deleted" %}', + { + accept: function() { + + // Keep track of each DELETE request + var requests = []; + + rows.forEach(function(row) { + requests.push( + inventreeDelete( + `/api/bom/${row.pk}/`, + ) + ); + }); + + // Wait for *all* the requests to complete + $.when.apply($, requests).then(function() { + location.reload(); + }); + } + } + ); + }); + + $('#bom-upload').click(function() { + location.href = "{% url 'upload-bom' part.id %}"; + }); + + $('#bom-duplicate').click(function() { + launchModalForm( + "{% url 'duplicate-bom' part.id %}", + { + success: function() { + $('#bom-table').bootstrapTable('refresh'); + } + } + ); + }); + + $("#bom-item-new").click(function () { + launchModalForm( + "{% url 'bom-item-create' %}?parent={{ part.id }}", + { + success: function() { + $("#bom-table").bootstrapTable('refresh'); + }, + secondary: [ + { + field: 'sub_part', + label: '{% trans "New Part" %}', + title: '{% trans "Create New Part" %}', + url: "{% url 'part-create' %}", + }, + ] + } + ); + }); + + {% else %} + + $("#validate-bom").click(function() { + launchModalForm( + "{% url 'bom-validate' part.id %}", + { + reload: true, + } + ); + }); + + $("#edit-bom").click(function () { + location.href = "{% url 'part-detail' part.id %}?display=bom&edit=1"; + }); + + $("#download-bom").click(function () { + launchModalForm("{% url 'bom-export' part.id %}", + { + success: function(response) { + location.href = response.url; + }, + } + ); + }); + + {% endif %} + + $("#print-bom-report").click(function() { + printBomReports([{{ part.pk }}]); + }); + + $("#start-build").click(function() { + newBuildOrder({ + part: {{ part.pk }}, + }); + }); + + loadBuildTable($("#build-table"), { + url: "{% url 'api-build-list' %}", + params: { + part: {{ part.id }}, + } + }); + + $('#table-related-part').inventreeTable({ + }); + + $("#add-related-part").click(function() { + launchModalForm("{% url 'part-related-create' %}", { + data: { + part: {{ part.id }}, + }, + reload: true, + }); + }); + + $('.delete-related-part').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + + loadPartVariantTable($('#variants-table'), {{ part.pk }}); + + $('#new-variant').click(function() { + launchModalForm( + "{% url 'make-part-variant' part.id %}", + { + follow: true, + } + ); + }); + + loadPurchaseOrderTable($("#purchase-order-table"), { + url: "{% url 'api-po-list' %}", + params: { + part: {{ part.id }}, + }, + }); + + $("#part-order2").click(function() { + launchModalForm("{% url 'order-parts' %}", { + data: { + part: {{ part.id }}, + }, + reload: true, + }); + }); + + loadSalesOrderTable($("#sales-order-table"), { + url: "{% url 'api-so-list' %}", + params: { + part: {{ part.id }}, + }, + }); + + loadPartTestTemplateTable( + $("#test-template-table"), + { + part: {{ part.pk }}, + params: { + part: {{ part.pk }}, + } + } + ); + + function reloadTable() { + $("#test-template-table").bootstrapTable("refresh"); + } + + $("#add-test-template").click(function() { + + constructForm('{% url "api-part-test-template-list" %}', { + method: 'POST', + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result Template" %}', + onSuccess: reloadTable + }); + }); + + $("#test-template-table").on('click', '.button-test-edit', function() { + var pk = $(this).attr('pk'); + + var url = `/api/part/test-template/${pk}/`; + + constructForm(url, { + fields: { + test_name: {}, + description: {}, + required: {}, + requires_value: {}, + requires_attachment: {}, + }, + title: '{% trans "Edit Test Result Template" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-template-table").on('click', '.button-test-delete', function() { + var pk = $(this).attr('pk'); + + var url = `/api/part/test-template/${pk}/`; + + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result Template" %}', + onSuccess: reloadTable, + }); + }); + + $('#add-stock-item').click(function () { + createNewStockItem({ + reload: true, + data: { + part: {{ part.id }}, + } + }); + }); + + loadStockTable($("#stock-table"), { + params: { + part: {{ part.id }}, + location_detail: true, + part_detail: true, + supplier_part_detail: true, + }, + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", + }); + + $("#stock-export").click(function() { + + exportStock({ + part: {{ part.pk }} + }); + }); + + $('#item-create').click(function () { + createNewStockItem({ + reload: true, + data: { + part: {{ part.id }}, + } + }); + }); + + $('#edit-notes').click(function() { + constructForm('{% url "api-part-detail" part.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Part Notes" %}', + reload: true, + }); + }); + $(".slidey").change(function() { var field = $(this).attr('fieldname'); @@ -263,4 +689,356 @@ ); }); + loadPartParameterTable( + '#parameter-table', + '{% url "api-part-parameter-list" %}', + { + params: { + part: {{ part.pk }}, + } + } + ); + + $('#param-table').inventreeTable({ + }); + + {% if roles.part.add %} + $('#param-create').click(function() { + + constructForm('{% url "api-part-parameter-list" %}', { + method: 'POST', + fields: { + part: { + value: {{ part.pk }}, + hidden: true, + }, + template: {}, + data: {}, + }, + title: '{% trans "Add Parameter" %}', + onSuccess: function() { + $('#parameter-table').bootstrapTable('refresh'); + } + }); + }); + {% endif %} + + $('.param-edit').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + + $('.param-delete').click(function() { + var button = $(this); + + launchModalForm(button.attr('url'), { + reload: true, + }); + }); + + loadAttachmentTable( + '{% url "api-part-attachment-list" %}', + { + filters: { + part: {{ part.pk }}, + }, + onEdit: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + }, + onDelete: function(pk) { + var url = `/api/part/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + enableDragAndDrop( + '#attachment-dropzone', + '{% url "api-part-attachment-list" %}', + { + data: { + part: {{ part.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm( + '{% url "api-part-attachment-list" %}', + { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + part: { + value: {{ part.pk }}, + hidden: true, + } + }, + onSuccess: reloadAttachmentTable, + title: '{% trans "Add Attachment" %}', + } + ) + }); + + function reloadSupplierPartTable() { + $('#supplier-part-table').bootstrapTable('refresh'); + } + + $('#supplier-create').click(function () { + + createSupplierPart({ + part: {{ part.pk }}, + onSuccess: reloadSupplierPartTable, + }); + }); + + $("#supplier-part-delete").click(function() { + + var selections = $("#supplier-part-table").bootstrapTable("getSelections"); + + var requests = []; + + showQuestionDialog( + '{% trans "Delete Supplier Parts?" %}', + '{% trans "All selected supplier parts will be deleted" %}', + { + accept: function() { + selections.forEach(function(part) { + var url = `/api/company/part/${part.pk}/`; + + requests.push(inventreeDelete(url)); + }); + + $.when.apply($, requests).then(function() { + reloadSupplierPartTable(); + }); + } + } + ); + }); + + loadSupplierPartTable( + "#supplier-part-table", + "{% url 'api-supplier-part-list' %}", + { + params: { + part: {{ part.id }}, + part_detail: false, + supplier_detail: true, + manufacturer_detail: true, + }, + } + ); + + linkButtonsToSelection($("#supplier-part-table"), ['#supplier-part-options']); + + loadManufacturerPartTable( + '#manufacturer-part-table', + "{% url 'api-manufacturer-part-list' %}", + { + params: { + part: {{ part.id }}, + part_detail: true, + manufacturer_detail: true, + }, + } + ); + + linkButtonsToSelection($("#manufacturer-part-table"), ['#manufacturer-part-options']); + + $("#manufacturer-part-delete").click(function() { + + var selections = $("#manufacturer-part-table").bootstrapTable("getSelections"); + + deleteManufacturerParts(selections, { + onSuccess: function() { + $("#manufacturer-part-table").bootstrapTable("refresh"); + } + }); + }); + + $('#manufacturer-create').click(function () { + + createManufacturerPart({ + part: {{ part.pk }}, + onSuccess: function() { + $("#manufacturer-part-table").bootstrapTable("refresh"); + } + }); + }); + + {% default_currency as currency %} + + // history graphs + {% if price_history %} + var purchasepricedata = { + labels: [ + {% for line in price_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Single Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in price_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line' + }, + {% if 'price_diff' in price_history.0 %} + { + label: '{% blocktrans %}Single Price Difference - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(68, 157, 68, 0.2)', + borderColor: 'rgb(68, 157, 68)', + yAxisID: 'y2', + data: [ + {% for line in price_history %}{{ line.price_diff|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line', + hidden: true, + }, + { + label: '{% blocktrans %}Part Single Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(70, 127, 155, 0.2)', + borderColor: 'rgb(70, 127, 155)', + yAxisID: 'y', + data: [ + {% for line in price_history %}{{ line.price_part|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + type: 'line', + hidden: true, + }, + {% endif %} + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in price_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1 + }] + } + var StockPriceChart = loadStockPricingChart($('#StockPriceChart'), purchasepricedata) + {% endif %} + + {% if bom_parts %} + var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) + var bomdata = { + labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], + datasets: [ + { + label: 'Price', + data: [{% for line in bom_parts %}{{ line.min_price }},{% endfor %}], + backgroundColor: bom_colors, + }, + {% if bom_pie_max %} + { + label: 'Max Price', + data: [{% for line in bom_parts %}{{ line.max_price }},{% endfor %}], + backgroundColor: bom_colors, + }, + {% endif %} + ] + }; + var BomChart = loadBomChart(document.getElementById('BomChart'), bomdata) + {% endif %} + + + // Internal pricebreaks + {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} + {% if show_internal_price and roles.sales_order.view %} + initPriceBreakSet( + $('#internal-price-break-table'), + { + part_id: {{part.id}}, + pb_human_name: 'internal price break', + pb_url_slug: 'internal-price', + pb_url: '{% url 'api-part-internal-price-list' %}', + pb_new_btn: $('#new-internal-price-break'), + pb_new_url: '{% url 'internal-price-break-create' %}', + linkedGraph: $('#InternalPriceBreakChart'), + }, + ); + {% endif %} + + // Sales pricebreaks + {% if part.salable and roles.sales_order.view %} + initPriceBreakSet( + $('#price-break-table'), + { + part_id: {{part.id}}, + pb_human_name: 'sale price break', + pb_url_slug: 'sale-price', + pb_url: "{% url 'api-part-sale-price-list' %}", + pb_new_btn: $('#new-price-break'), + pb_new_url: '{% url 'sale-price-break-create' %}', + linkedGraph: $('#SalePriceBreakChart'), + }, + ); + {% endif %} + + // Sale price history + {% if sale_history %} + var salepricedata = { + labels: [ + {% for line in sale_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in sale_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + }, + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in sale_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1, + type: 'bar', + }] + } + var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata) + {% endif %} + + attachNavCallbacks({ + name: 'part', + default: 'part-stock' + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/import_wizard/ajax_match_fields.html b/InvenTree/part/templates/part/import_wizard/ajax_match_fields.html new file mode 100644 index 0000000000..293ddbc4d8 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/ajax_match_fields.html @@ -0,0 +1,89 @@ +{% extends "part/import_wizard/ajax_part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if missing_columns and missing_columns|length > 0 %} + +{% endif %} +{% if duplicates and duplicates|length > 0 %} + +{% endif %} +{% endblock form_alert %} + +{% block form_content %} + + + {% trans "File Fields" %} + + {% for col in form %} + +
                  + + {{ col.name }} + +
                  + + {% endfor %} + + + + + {% trans "Match Fields" %} + + {% for col in form %} + + {{ col }} + {% for duplicate in duplicates %} + {% if duplicate == col.value %} + + {% endif %} + {% endfor %} + + {% endfor %} + + {% for row in rows %} + {% with forloop.counter as row_index %} + + + + + {{ row_index }} + {% for item in row.data %} + + + {{ item }} + + {% endfor %} + + {% endwith %} + {% endfor %} + +{% endblock form_content %} + +{% block js_ready %} +{{ block.super }} + +$('.fieldselect').select2({ + width: '100%', + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/ajax_match_references.html b/InvenTree/part/templates/part/import_wizard/ajax_match_references.html new file mode 100644 index 0000000000..e57fb066d3 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/ajax_match_references.html @@ -0,0 +1,84 @@ +{% extends "part/import_wizard/ajax_part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} +{% load crispy_forms_tags %} + +{% block form_alert %} +{% if form.errors %} +{% endif %} +{% if form_errors %} + +{% endif %} +{% endblock form_alert %} + +{% block form_content %} + + + + {% trans "Row" %} + {% for col in columns %} + + + + + {% if col.guess %} + {{ col.guess }} + {% else %} + {{ col.name }} + {% endif %} + + {% endfor %} + + + + {% comment %} Dummy row for javascript del_row method {% endcomment %} + {% for row in rows %} + + + + + + {% add row.index 1 %} + + {% for item in row.data %} + + {% if item.column.guess %} + {% with row_name=item.column.guess|lower %} + {% for field in form.visible_fields %} + {% if field.name == row|keyvalue:row_name %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% endwith %} + {% else %} + {{ item.cell }} + {% endif %} + + + {% endfor %} + + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.bomselect').select2({ + dropdownAutoWidth: true, + matcher: partialMatcher, +}); + +$('.currencyselect').select2({ + dropdownAutoWidth: true, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/ajax_part_upload.html b/InvenTree/part/templates/part/import_wizard/ajax_part_upload.html new file mode 100644 index 0000000000..f2a1e5c844 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/ajax_part_upload.html @@ -0,0 +1,33 @@ +{% extends "modal_form.html" %} + +{% load inventree_extras %} +{% load i18n %} + +{% block form %} + +{% if roles.part.change %} + +

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

                  + + {% block form_alert %} + {% endblock form_alert %} + +
                  + {% csrf_token %} + {% load crispy_forms_tags %} + + + {{ wizard.management_form }} + {% block form_content %} + {% crispy wizard.form %} + {% endblock form_content %} +
                  + +{% else %} + +{% endif %} +
                +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/match_fields.html b/InvenTree/part/templates/part/import_wizard/match_fields.html new file mode 100644 index 0000000000..ba709bc639 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_fields.html @@ -0,0 +1,99 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block form_alert %} +{% if missing_columns and missing_columns|length > 0 %} + +{% endif %} +{% if duplicates and duplicates|length > 0 %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + {% trans "File Fields" %} + + {% for col in form %} + +
                + + {{ col.name }} + +
                + + {% endfor %} + + + + + {% trans "Match Fields" %} + + {% for col in form %} + + {{ col }} + {% for duplicate in duplicates %} + {% if duplicate == col.value %} + + {% endif %} + {% endfor %} + + {% endfor %} + + {% for row in rows %} + {% with forloop.counter as row_index %} + + + + + {{ row_index }} + {% for item in row.data %} + + + {{ item }} + + {% endfor %} + + {% endwith %} + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.fieldselect').select2({ + width: '100%', + matcher: partialMatcher, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/match_references.html b/InvenTree/part/templates/part/import_wizard/match_references.html new file mode 100644 index 0000000000..99b9ccd191 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/match_references.html @@ -0,0 +1,91 @@ +{% extends "part/import_wizard/part_upload.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} +{% load crispy_forms_tags %} + +{% block form_alert %} +{% if form.errors %} +{% endif %} +{% if form_errors %} + +{% endif %} +{% endblock form_alert %} + +{% block form_buttons_top %} + {% if wizard.steps.prev %} + + {% endif %} + +{% endblock form_buttons_top %} + +{% block form_content %} + + + + {% trans "Row" %} + {% for col in columns %} + + + + + {% if col.guess %} + {{ col.guess }} + {% else %} + {{ col.name }} + {% endif %} + + {% endfor %} + + + + {% comment %} Dummy row for javascript del_row method {% endcomment %} + {% for row in rows %} + + + + + + {% add row.index 1 %} + + {% for item in row.data %} + + {% if item.column.guess %} + {% with row_name=item.column.guess|lower %} + {% for field in form.visible_fields %} + {% if field.name == row|keyvalue:row_name %} + {{ field|as_crispy_field }} + {% endif %} + {% endfor %} + {% endwith %} + {% else %} + {{ item.cell }} + {% endif %} + + + {% endfor %} + + {% endfor %} + +{% endblock form_content %} + +{% block form_buttons_bottom %} +{% endblock form_buttons_bottom %} + +{% block js_ready %} +{{ block.super }} + +$('.bomselect').select2({ + dropdownAutoWidth: true, + matcher: partialMatcher, +}); + +$('.currencyselect').select2({ + dropdownAutoWidth: true, +}); + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/import_wizard/part_upload.html b/InvenTree/part/templates/part/import_wizard/part_upload.html new file mode 100644 index 0000000000..676053bbe5 --- /dev/null +++ b/InvenTree/part/templates/part/import_wizard/part_upload.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} +{% load inventree_extras %} +{% load i18n %} +{% load static %} + +{% block content %} +
                +
                +

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

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

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

                + + {% block form_alert %} + {% endblock form_alert %} + + + {% csrf_token %} + {% load crispy_forms_tags %} + + {% block form_buttons_top %} + {% endblock form_buttons_top %} + + + {{ wizard.management_form }} + {% block form_content %} + {% crispy wizard.form %} + {% endblock form_content %} +
                + + {% block form_buttons_bottom %} + {% if wizard.steps.prev %} + + {% endif %} + + + {% endblock form_buttons_bottom %} + + {% else %} + + {% endif %} +
                +
                +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/internal_prices.html b/InvenTree/part/templates/part/internal_prices.html deleted file mode 100644 index 2f54f3bb64..0000000000 --- a/InvenTree/part/templates/part/internal_prices.html +++ /dev/null @@ -1,122 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='internal-prices' %} -{% endblock %} - -{% block heading %} -{% trans "Internal Price Information" %} -{% endblock %} - -{% block details %} -{% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} -{% if show_internal_price and roles.sales_order.view %} -
                - -
                - - -
                - -{% else %} -
                -

                {% trans "Permission Denied" %}

                - -
                - {% trans "You do not have permission to view this page." %} -
                -
                -{% endif %} -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} -{% if show_internal_price and roles.sales_order.view %} -function reloadPriceBreaks() { - $("#internal-price-break-table").bootstrapTable("refresh"); -} - -$('#new-internal-price-break').click(function() { - launchModalForm("{% url 'internal-price-break-create' %}", - { - success: reloadPriceBreaks, - data: { - part: {{ part.id }}, - } - } - ); -}); - -$('#internal-price-break-table').inventreeTable({ - name: 'internalprice', - formatNoMatches: function() { return "{% trans 'No internal price break information found' %}"; }, - queryParams: { - part: {{ part.id }}, - }, - url: "{% url 'api-part-internal-price-list' %}", - onPostBody: function() { - var table = $('#internal-price-break-table'); - - table.find('.button-internal-price-break-delete').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/part/internal-price/${pk}/delete/`, - { - success: reloadPriceBreaks - } - ); - }); - - table.find('.button-internal-price-break-edit').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/part/internal-price/${pk}/edit/`, - { - success: reloadPriceBreaks - } - ); - }); - }, - columns: [ - { - field: 'pk', - title: 'ID', - visible: false, - switchable: false, - }, - { - field: 'quantity', - title: '{% trans "Quantity" %}', - sortable: true, - }, - { - field: 'price', - title: '{% trans "Price" %}', - sortable: true, - formatter: function(value, row, index) { - var html = value; - - html += `
                ` - - html += makeIconButton('fa-edit icon-blue', 'button-internal-price-break-edit', row.pk, '{% trans "Edit internal price break" %}'); - html += makeIconButton('fa-trash-alt icon-red', 'button-internal-price-break-delete', row.pk, '{% trans "Delete internal price break" %}'); - - html += `
                `; - - return html; - } - }, - ] -}) - -{% endif %} -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/manufacturer.html b/InvenTree/part/templates/part/manufacturer.html deleted file mode 100644 index 82f02ba85f..0000000000 --- a/InvenTree/part/templates/part/manufacturer.html +++ /dev/null @@ -1,92 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='manufacturers' %} -{% endblock %} - -{% block heading %} -{% trans "Part Manufacturers" %} -{% endblock %} - -{% block details %} - -
                -
                - -
                - - -
                -
                -
                - - -
                - -{% endblock %} - -{% block js_load %} -{{ block.super }} -{% endblock %} -{% block js_ready %} - {{ block.super }} - - $('#manufacturer-create').click(function () { - launchModalForm( - "{% url 'manufacturer-part-create' %}", - { - reload: true, - data: { - part: {{ part.id }} - }, - secondary: [ - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new manufacturer" %}', - url: "{% url 'manufacturer-create' %}", - } - ] - }); - }); - - $("#manufacturer-part-delete").click(function() { - - var selections = $("#manufacturer-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'manufacturer-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); - }); - - loadManufacturerPartTable( - "#manufacturer-table", - "{% url 'api-manufacturer-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: false, - manufacturer_detail: true, - }, - } - ); - - linkButtonsToSelection($("#manufacturer-table"), ['#manufacturer-part-options']) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/navbar.html b/InvenTree/part/templates/part/navbar.html index c0bc4c96a3..a2dc67c079 100644 --- a/InvenTree/part/templates/part/navbar.html +++ b/InvenTree/part/templates/part/navbar.html @@ -3,6 +3,7 @@ {% load inventree_extras %} {% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} +{% settings_value 'PART_SHOW_RELATED' as show_related %}
                • @@ -10,52 +11,36 @@
                • -
                • - - - - {% trans "Details" %} - - -
                • -
                • - - +
                • + + {% trans "Parameters" %}
                • {% if part.is_template %} -
                • - +
                • + {% trans "Variants" %}
                • {% endif %} -
                • - +
                • + {% trans "Stock" %}
                • - {% if part.component or part.salable %} -
                • - - - {% trans "Allocations" %} - -
                • - {% endif %} {% if part.assembly %} -
                • - +
                • + {% trans "Bill of Materials" %}
                • {% if roles.build.view %} -
                • - +
                • + {% trans "Build Orders" %} @@ -63,82 +48,66 @@ {% endif %} {% endif %} {% if part.component %} -
                • - +
                • + {% trans "Used In" %}
                • {% endif %} - {% if part.purchaseable and roles.purchase_order.view %} -
                • - +
                • + - {% trans "Order Price" %} + {% trans "Prices" %}
                • -
                • - - - {% trans "Manufacturers" %} - -
                • -
                • - + {% if part.purchaseable and roles.purchase_order.view %} +
                • + {% trans "Suppliers" %}
                • -
                • - +
                • + {% trans "Purchase Orders" %}
                • {% endif %} - {% if show_internal_price and roles.sales_order.view %} -
                • - - - {% trans "Internal Price" %} - -
                • -
                • - - - {% trans "Sale Price" %} - -
                • -
                • - + {% if roles.sales_order.view %} +
                • + {% trans "Sales Orders" %}
                • {% endif %} {% if part.trackable %} -
                • - +
                • + - {% trans "Tests" %} + {% trans "Test Templates" %}
                • {% endif %} -
                • - + {% if show_related %} +
                • + {% trans "Related Parts" %}
                • -
                • - - + {% endif %} +
                • + + {% trans "Attachments" %}
                • -
                • - - +
                • + + {% trans "Notes" %}
                • diff --git a/InvenTree/part/templates/part/notes.html b/InvenTree/part/templates/part/notes.html deleted file mode 100644 index 63e0190d48..0000000000 --- a/InvenTree/part/templates/part/notes.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load crispy_forms_tags %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='notes' %} -{% endblock %} - -{% block heading %} -{% trans "Part Notes" %} -{% if roles.part.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} - -{% if editing %} -
                  - {% csrf_token %} - - {{ form }} -
                  - - - -
                  - -{{ form.media }} - -{% else %} - -
                  - {% if part.notes %} -
                  - {{ part.notes | markdownify }} -
                  - {% endif %} -
                  - -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'part-notes' part.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/order_prices.html b/InvenTree/part/templates/part/order_prices.html deleted file mode 100644 index 5e5552c5f9..0000000000 --- a/InvenTree/part/templates/part/order_prices.html +++ /dev/null @@ -1,235 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load crispy_forms_tags %} -{% load inventree_extras %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='order-prices' %} -{% endblock %} - -{% block heading %} -{% trans "Order Price Information" %} -{% endblock %} - -{% block details %} -{% default_currency as currency %} -{% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} - -
                  - {% csrf_token %} -
                  -
                  {{ form|crispy }}
                  -
                  - -
                  -
                  -
                  -
                  - -
                  -

                  {% trans "Pricing ranges" %}

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

                  {% trans 'BOM Pricing' %}

                  -
                  - -
                  -
                  -{% endif %} -
                  - -{% if price_history %} -
                  -

                  {% trans 'Stock Pricing' %}

                  - {% if price_history|length > 0 %} -
                  - -
                  - {% else %} -
                  - {% trans 'No stock pricing history is available for this part.' %} -
                  - {% endif %} -{% endif %} -{% endblock %} - - - - -{% block js_ready %} - {{ block.super }} - - {% default_currency as currency %} - {% if price_history %} - var pricedata = { - labels: [ - {% for line in price_history %}'{{ line.date }}',{% endfor %} - ], - datasets: [{ - label: '{% blocktrans %}Single Price - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(255, 99, 132, 0.2)', - borderColor: 'rgb(255, 99, 132)', - yAxisID: 'y', - data: [ - {% for line in price_history %}{{ line.price|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line' - }, - {% if 'price_diff' in price_history.0 %} - { - label: '{% blocktrans %}Single Price Difference - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(68, 157, 68, 0.2)', - borderColor: 'rgb(68, 157, 68)', - yAxisID: 'y2', - data: [ - {% for line in price_history %}{{ line.price_diff|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line', - hidden: true, - }, - { - label: '{% blocktrans %}Part Single Price - {{currency}}{% endblocktrans %}', - backgroundColor: 'rgba(70, 127, 155, 0.2)', - borderColor: 'rgb(70, 127, 155)', - yAxisID: 'y', - data: [ - {% for line in price_history %}{{ line.price_part|stringformat:".2f" }},{% endfor %} - ], - borderWidth: 1, - type: 'line', - hidden: true, - }, - {% endif %} - { - label: '{% trans "Quantity" %}', - backgroundColor: 'rgba(255, 206, 86, 0.2)', - borderColor: 'rgb(255, 206, 86)', - yAxisID: 'y1', - data: [ - {% for line in price_history %}{{ line.qty|stringformat:"f" }},{% endfor %} - ], - borderWidth: 1 - }] - } - var StockPriceChart = loadStockPricingChart(document.getElementById('StockPriceChart'), pricedata) - var bom_colors = randomColor({hue: 'green', count: {{ bom_parts|length }} }) - var bomdata = { - labels: [{% for line in bom_parts %}'{{ line.name }}',{% endfor %}], - datasets: [ - { - label: 'Price', - data: [{% for line in bom_parts %}{{ line.min_price }},{% endfor %}], - backgroundColor: bom_colors, - }, - {% if bom_pie_max %} - { - label: 'Max Price', - data: [{% for line in bom_parts %}{{ line.max_price }},{% endfor %}], - backgroundColor: bom_colors, - }, - {% endif %} - ] - }; - var BomChart = loadBomChart(document.getElementById('BomChart'), bomdata) - - {% endif %} - -{% endblock %} diff --git a/InvenTree/part/templates/part/orders.html b/InvenTree/part/templates/part/orders.html deleted file mode 100644 index 24a1cdbf3c..0000000000 --- a/InvenTree/part/templates/part/orders.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='orders' %} -{% endblock %} - -{% block heading %} -{% trans "Purchase Orders" %} -{% endblock %} - -{% block details %} - -
                  -
                  - -
                  - -
                  -
                  -
                  - - -
                  - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPurchaseOrderTable($("#purchase-order-table"), { - url: "{% url 'api-po-list' %}", - params: { - part: {{ part.id }}, - }, -}); - -$("#part-order2").click(function() { - launchModalForm("{% url 'order-parts' %}", { - data: { - part: {{ part.id }}, - }, - reload: true, - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/param_delete.html b/InvenTree/part/templates/part/param_delete.html deleted file mode 100644 index efb8ca3c26..0000000000 --- a/InvenTree/part/templates/part/param_delete.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "modal_delete_form.html" %} - -{% block pre_form_content %} -Are you sure you want to remove this parameter? -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/params.html b/InvenTree/part/templates/part/params.html deleted file mode 100644 index e1c21cd681..0000000000 --- a/InvenTree/part/templates/part/params.html +++ /dev/null @@ -1,92 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "part/navbar.html" with tab='params' %} -{% endblock %} - -{% block heading %} -{% trans "Part Parameters" %} -{% endblock %} - -{% block details %} -
                  -
                  - {% if roles.part.add %} - - {% endif %} -
                  -
                  - - - - - - - - - - - {% for param in part.get_parameters %} - - - - - - {% endfor %} - -
                  {% trans "Name" %}{% trans "Value" %}{% trans "Units" %}
                  {{ param.template.name }}{{ param.data }} - {{ param.template.units }} -
                  - {% if roles.part.change %} - - {% endif %} - {% if roles.part.change %} - - {% endif %} -
                  -
                  - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - $('#param-table').inventreeTable({ - }); - - {% if roles.part.add %} - $('#param-create').click(function() { - launchModalForm("{% url 'part-param-create' %}?part={{ part.id }}", { - reload: true, - secondary: [{ - field: 'template', - label: '{% trans "New Template" %}', - title: '{% trans "Create New Parameter Template" %}', - url: "{% url 'part-param-template-create' %}" - }], - }); - }); - {% endif %} - - $('.param-edit').click(function() { - var button = $(this); - - launchModalForm(button.attr('url'), { - reload: true, - }); - }); - - $('.param-delete').click(function() { - var button = $(this); - - launchModalForm(button.attr('url'), { - reload: true, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index b486e2c589..9fe6c7b486 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -27,7 +27,34 @@
                {% endif %} + {% if part.description %}

                {{ part.description }}

                + {% endif %} +

                +

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

                {% if roles.stock.change %} - + {% endif %} {% if part.purchaseable %} {% if roles.purchase_order.add %} @@ -81,11 +124,11 @@
                - {% if part.IPN %} + {% if part.keywords %} - - - + + + {% endif %} {% if part.link %} @@ -96,7 +139,22 @@ {% endif %} + + + + {% if part.trackable and part.getLatestSerialNumber %} + + + + + + {% endif %}
                {% trans "IPN" %}{{ part.IPN }}{% trans "Keywords" %}{{ part.keywords }}
                {% trans "Creation Date" %} + {{ part.creation_date }} + {% if part.creation_user %} + {{ part.creation_user }} + {% endif %} +
                {% trans "Latest Serial Number" %}{{ part.getLatestSerialNumber }}{% include "clip.html"%}
                @@ -109,7 +167,7 @@ {% endif %} {% if part.variant_of %}
                - {% object_link 'part-variants' part.variant_of.id part.variant_of.full_name as link %} + {% object_link 'part-detail' part.variant_of.id part.variant_of.full_name as link %} {% blocktrans %}This part is a variant of {{link}}{% endblocktrans %}
                {% endif %} @@ -181,44 +239,13 @@ {% endif %} {% endif %} {% endif %} - {% if part.trackable and part.getLatestSerialNumber %} - - - - {% trans "Latest Serial Number" %} - {{ part.getLatestSerialNumber }}{% include "clip.html"%} - - {% endif %}
                -{% block pre_content_panel %} - -{% endblock %} - -
                - - -
                -

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

                -
                - -
                - {% block details %} - - {% endblock %} -
                - -
                -{% block post_content_panel %} - +{% block page_content %} {% endblock %} {% endblock %} @@ -226,17 +253,22 @@ {% block js_ready %} {{ block.super }} - enableNavbar({ - label: 'part', - toggleId: '#part-menu-toggle', - }); - {% if part.image %} $('#part-thumb').click(function() { showModalImage('{{ part.image.url }}'); }); {% endif %} + function reloadImage(data) { + // If image / thumbnail data present, live update + if (data.image) { + $('#part-image').attr('src', data.image); + } else { + // Otherwise, reload the page + location.reload(); + } + } + enableDragAndDrop( '#part-thumb', "{% url 'api-part-detail' part.id %}", @@ -244,14 +276,7 @@ label: 'image', method: 'PATCH', success: function(data, status, xhr) { - - // If image / thumbnail data present, live update - if (data.image) { - $('#part-image').attr('src', data.image); - } else { - // Otherwise, reload the page - location.reload(); - } + reloadImage(data); } } ); @@ -265,14 +290,38 @@ ); }); - $("#part-count").click(function() { - launchModalForm("/stock/adjust/", { - data: { - action: "count", + $('#print-label').click(function() { + printPartLabels([{{ part.pk }}]); + }); + + function adjustPartStock(action) { + inventreeGet( + '{% url "api-stock-list" %}', + { part: {{ part.id }}, + in_stock: true, + allow_variants: true, + part_detail: true, + location_detail: true, }, - reload: true, - }); + { + success: function(items) { + adjustStock(action, items, { + onSuccess: function() { + location.reload(); + } + }); + }, + } + ); + } + + $("#part-move").click(function() { + adjustPartStock('move'); + }); + + $("#part-count").click(function() { + adjustPartStock('count'); }); $("#price-button").click(function() { @@ -293,11 +342,20 @@ }); $("#part-image-upload").click(function() { - launchModalForm("{% url 'part-image-upload' part.id %}", + + constructForm( + '{% url "api-part-detail" part.pk %}', { - reload: true + method: 'PATCH', + fields: { + image: {}, + }, + title: '{% trans "Upload Image" %}', + onSuccess: function(data) { + reloadImage(data); + } } - ); + ) }); @@ -357,12 +415,8 @@ }); $("#part-edit").click(function() { - launchModalForm( - "{% url 'part-edit' part.id %}", - { - reload: true, - } - ); + + editPart({{ part.pk }}); }); {% endif %} diff --git a/InvenTree/part/templates/part/part_tests.html b/InvenTree/part/templates/part/part_tests.html deleted file mode 100644 index dbd439afdb..0000000000 --- a/InvenTree/part/templates/part/part_tests.html +++ /dev/null @@ -1,78 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='tests' %} -{% endblock %} - -{% block heading %} -{% trans "Part Test Templates" %} -{% endblock %} - -{% block details %} -
                -
                -
                - -
                -
                - -
                -
                -
                - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadPartTestTemplateTable( - $("#test-template-table"), - { - part: {{ part.pk }}, - params: { - part: {{ part.pk }}, - } - } -); - -function reloadTable() { - $("#test-template-table").bootstrapTable("refresh"); -} - -$("#add-test-template").click(function() { - launchModalForm( - "{% url 'part-test-template-create' %}", - { - data: { - part: {{ part.id }}, - }, - success: reloadTable, - } - ); -}); - -$("#test-template-table").on('click', '.button-test-edit', function() { - var button = $(this); - - var url = `/part/test-template/${button.attr('pk')}/edit/`; - - launchModalForm(url, { - success: reloadTable, - }); -}); - -$("#test-template-table").on('click', '.button-test-delete', function() { - var button = $(this); - - var url = `/part/test-template/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - success: reloadTable, - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html new file mode 100644 index 0000000000..7581d659e1 --- /dev/null +++ b/InvenTree/part/templates/part/prices.html @@ -0,0 +1,282 @@ +{% load static %} +{% load i18n %} +{% load crispy_forms_tags %} +{% load inventree_extras %} + +
                +

                {% trans "Pricing Information" %}

                +
                + +{% default_currency as currency %} +
                + +
                + +
                +

                {% trans "Pricing ranges" %}

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

                {% trans "Calculation parameters" %}

                +
                + {% csrf_token %} + {{ form|crispy }} + +
                +
                +
                +
                + +{% settings_value "PART_INTERNAL_PRICE" as show_internal_price %} + +{% if part.purchaseable and roles.purchase_order.view %} + +
                +

                {% trans "Supplier Cost" %} + +

                +
                + +
                +
                +
                +

                {% trans "Suppliers" %}

                +
                +
                +
                +

                {% trans "Manufacturers" %}

                +
                +
                +
                +
                + +{% if price_history %} + +
                +

                {% trans "Purchase Price" %} + +

                +
                +
                +

                {% trans 'Stock Pricing' %} + +

                + {% if price_history|length > 0 %} +
                + +
                + {% else %} +
                + {% trans 'No stock pricing history is available for this part.' %} +
                + {% endif %} +
                +{% endif %} +{% endif %} + +{% if show_internal_price and roles.sales_order.view %} + +
                +

                {% trans "Internal Cost" %} + +

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

                {% trans "BOM Cost" %} + +

                +
                + +
                +
                +
                +
                +
                + + {% if part.bom_count > 0 %} +
                +

                {% trans 'BOM Pricing' %}

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

                {% trans "Sale Cost" %} + +

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

                {% trans "Sale Price" %} + +

                +
                + +
                + {% if sale_history|length > 0 %} +
                + +
                + {% else %} +
                + {% trans 'No sale pice history available for this part.' %} +
                + {% endif %} +
                +{% endif %} diff --git a/InvenTree/part/templates/part/related.html b/InvenTree/part/templates/part/related.html deleted file mode 100644 index 77c2e1bc9f..0000000000 --- a/InvenTree/part/templates/part/related.html +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='related' %} -{% endblock %} - -{% block heading %} -{% trans "Related Parts" %} -{% endblock %} - -{% block details %} - -
                -
                - {% if roles.part.change %} - - - {% endif %} -
                -
                - - - - - - - - - {% for item in part.get_related_parts %} - {% with part_related=item.0 part=item.1 %} - - - - {% endwith %} - {% endfor %} - - - - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - $('#table-related-part').inventreeTable({ - }); - - $("#add-related-part").click(function() { - launchModalForm("{% url 'part-related-create' %}", { - data: { - part: {{ part.id }}, - }, - reload: true, - }); - }); - - $('.delete-related-part').click(function() { - var button = $(this); - - launchModalForm(button.attr('url'), { - reload: true, - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/sale_prices.html b/InvenTree/part/templates/part/sale_prices.html deleted file mode 100644 index 4ec826e2a6..0000000000 --- a/InvenTree/part/templates/part/sale_prices.html +++ /dev/null @@ -1,108 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='sales-prices' %} -{% endblock %} - -{% block heading %} -{% trans "Sell Price Information" %} -{% endblock %} - -{% block details %} - -
                - -
                - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -function reloadPriceBreaks() { - $("#price-break-table").bootstrapTable("refresh"); -} - -$('#new-price-break').click(function() { - launchModalForm("{% url 'sale-price-break-create' %}", - { - success: reloadPriceBreaks, - data: { - part: {{ part.id }}, - } - } - ); -}); - -$('#price-break-table').inventreeTable({ - name: 'saleprice', - formatNoMatches: function() { return "{% trans 'No price break information found' %}"; }, - queryParams: { - part: {{ part.id }}, - }, - url: "{% url 'api-part-sale-price-list' %}", - onPostBody: function() { - var table = $('#price-break-table'); - - table.find('.button-price-break-delete').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/part/sale-price/${pk}/delete/`, - { - success: reloadPriceBreaks - } - ); - }); - - table.find('.button-price-break-edit').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/part/sale-price/${pk}/edit/`, - { - success: reloadPriceBreaks - } - ); - }); - }, - columns: [ - { - field: 'pk', - title: 'ID', - visible: false, - switchable: false, - }, - { - field: 'quantity', - title: '{% trans "Quantity" %}', - sortable: true, - }, - { - field: 'price', - title: '{% trans "Price" %}', - sortable: true, - formatter: function(value, row, index) { - var html = value; - - html += `
                ` - - html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}'); - html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}'); - - html += `
                `; - - return html; - } - }, - ] -}) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/sales_orders.html b/InvenTree/part/templates/part/sales_orders.html deleted file mode 100644 index fa8d5dfd8a..0000000000 --- a/InvenTree/part/templates/part/sales_orders.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='sales-orders' %} -{% endblock %} - -{% block heading %} -{% trans "Sales Orders" %} -{% endblock %} - -{% block details %} - -
                -
                - {% if 0 %} - - {% endif %} -
                - -
                -
                -
                - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadSalesOrderTable($("#sales-order-table"), { - url: "{% url 'api-so-list' %}", - params: { - part: {{ part.id }}, - }, -}); - -{% endblock %} diff --git a/InvenTree/part/templates/part/stock.html b/InvenTree/part/templates/part/stock.html deleted file mode 100644 index 067eda66a8..0000000000 --- a/InvenTree/part/templates/part/stock.html +++ /dev/null @@ -1,76 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='stock' %} -{% endblock %} - -{% block heading %} -{% trans "Part Stock" %} -{% endblock %} - -{% block details %} -{% if part.is_template %} -
                - {% blocktrans with full_name=part.full_name%}Showing stock for all variants of {{full_name}}{% endblocktrans %} -
                -{% endif %} - -{% include "stock_table.html" %} - -{% endblock %} - -{% block js_load %} -{{ block.super }} -{% endblock %} -{% block js_ready %} -{{ block.super }} - - $('#add-stock-item').click(function () { - createNewStockItem({ - reload: true, - data: { - part: {{ part.id }}, - } - }); - }); - - loadStockTable($("#stock-table"), { - params: { - part: {{ part.id }}, - location_detail: true, - part_detail: false, - }, - groupByField: 'location', - buttons: [ - '#stock-options', - ], - url: "{% url 'api-stock-list' %}", - }); - - $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: "{% trans 'Export' %}", - success: function(response) { - var url = "{% url 'stock-export' %}"; - - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - url += "&part={{ part.id }}"; - - location.href = url; - }, - }); - }); - - $('#item-create').click(function () { - createNewStockItem({ - reload: true, - data: { - part: {{ part.id }}, - } - }); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/subcategory.html b/InvenTree/part/templates/part/subcategory.html deleted file mode 100644 index e9e0d27468..0000000000 --- a/InvenTree/part/templates/part/subcategory.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "part/category.html" %} - -{% load i18n %} -{% load inventree_extras %} -{% load static %} - -{% block menubar %} -{% include 'part/category_navbar.html' with tab='subcategories' %} -{% endblock %} - -{% block category_content %} - -
                - -
                -

                {% trans "Subcategories" %}

                -
                - -
                -
                - -
                - -
                -
                -
                - -
                - -
                -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - enableNavbar({ - label: 'category', - toggleId: '#category-menu-toggle', - }); - - loadPartCategoryTable($('#subcategory-table'), { - params: { - {% if category %} - parent: {{ category.pk }} - {% else %} - parent: 'null' - {% endif %} - } - }); - -{% endblock %} diff --git a/InvenTree/part/templates/part/supplier.html b/InvenTree/part/templates/part/supplier.html deleted file mode 100644 index 45d2d1d55c..0000000000 --- a/InvenTree/part/templates/part/supplier.html +++ /dev/null @@ -1,97 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='suppliers' %} -{% endblock %} - -{% block heading %} -{% trans "Part Suppliers" %} -{% endblock %} - -{% block details %} -
                -
                - -
                - - -
                -
                -
                - - -
                - -{% endblock %} - -{% block js_load %} -{{ block.super }} -{% endblock %} -{% block js_ready %} - {{ block.super }} - - $('#supplier-create').click(function () { - launchModalForm( - "{% url 'supplier-part-create' %}", - { - reload: true, - data: { - part: {{ part.id }} - }, - secondary: [ - { - field: 'supplier', - label: '{% trans "New Supplier" %}', - title: '{% trans "Create new supplier" %}', - url: "{% url 'supplier-create' %}" - }, - { - field: 'manufacturer', - label: '{% trans "New Manufacturer" %}', - title: '{% trans "Create new manufacturer" %}', - url: "{% url 'manufacturer-create' %}", - } - ] - }); - }); - - $("#supplier-part-delete").click(function() { - - var selections = $("#supplier-table").bootstrapTable("getSelections"); - - var parts = []; - - selections.forEach(function(item) { - parts.push(item.pk); - }); - - launchModalForm("{% url 'supplier-part-delete' %}", { - data: { - parts: parts, - }, - reload: true, - }); - }); - - loadSupplierPartTable( - "#supplier-table", - "{% url 'api-supplier-part-list' %}", - { - params: { - part: {{ part.id }}, - part_detail: false, - supplier_detail: true, - manufacturer_detail: true, - }, - } - ); - - linkButtonsToSelection($("#supplier-table"), ['#supplier-part-options']) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/track.html b/InvenTree/part/templates/part/track.html deleted file mode 100644 index 8e89419a11..0000000000 --- a/InvenTree/part/templates/part/track.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='track' %} -{% endblock %} - -{% block heading %} -{% trans "Part Tracking" %} -{% endblock %} - -{% block details %} -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/used_in.html b/InvenTree/part/templates/part/used_in.html deleted file mode 100644 index e7d8863d42..0000000000 --- a/InvenTree/part/templates/part/used_in.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "part/part_base.html" %} -{% load i18n %} - -{% block menubar %} -{% include 'part/navbar.html' with tab='used' %} -{% endblock %} - -{% block heading %} -{% trans "Assemblies" %} -{% endblock %} - -{% block details %} - -
                -
                - -
                -
                - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPartTable('#used-table', - '{% url "api-part-list" %}', - { - params: { - uses: {{ part.pk }}, - }, - filterTarget: '#filter-list-usedin', - } - ); - - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/variants.html b/InvenTree/part/templates/part/variants.html deleted file mode 100644 index 11a548ba49..0000000000 --- a/InvenTree/part/templates/part/variants.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends "part/part_base.html" %} -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "part/navbar.html" with tab='variants' %} -{% endblock %} - -{% block heading %} -{% trans "Part Variants" %} -{% endblock %} - -{% block details %} -
                -
                -
                - {% if part.is_template and part.active %} - - {% endif %} -
                -
                - -
                -
                -
                - - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - - loadPartVariantTable($('#variants-table'), {{ part.pk }}); - - $('#new-variant').click(function() { - launchModalForm( - "{% url 'make-part-variant' part.id %}", - { - follow: true, - } - ); - }); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index d606b12637..7700c5c61f 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -13,6 +13,107 @@ from InvenTree.status_codes import StockStatus from part.models import Part, PartCategory from stock.models import StockItem from company.models import Company +from common.models import InvenTreeSetting + + +class PartOptionsAPITest(InvenTreeAPITestCase): + """ + Tests for the various OPTIONS endpoints in the /part/ API + + Ensure that the required field details are provided! + """ + + roles = [ + 'part.add', + ] + + def setUp(self): + + super().setUp() + + def test_part(self): + """ + Test the Part API OPTIONS + """ + + actions = self.getActions(reverse('api-part-list'))['POST'] + + # Check that a bunch o' fields are contained + for f in ['assembly', 'component', 'description', 'image', 'IPN']: + self.assertTrue(f in actions.keys()) + + # Active is a 'boolean' field + active = actions['active'] + + self.assertTrue(active['default']) + self.assertEqual(active['help_text'], 'Is this part active?') + self.assertEqual(active['type'], 'boolean') + self.assertEqual(active['read_only'], False) + + # String field + ipn = actions['IPN'] + self.assertEqual(ipn['type'], 'string') + self.assertFalse(ipn['required']) + self.assertEqual(ipn['max_length'], 100) + self.assertEqual(ipn['help_text'], 'Internal Part Number') + + # Related field + category = actions['category'] + + self.assertEqual(category['type'], 'related field') + self.assertTrue(category['required']) + self.assertFalse(category['read_only']) + self.assertEqual(category['label'], 'Category') + self.assertEqual(category['model'], 'partcategory') + self.assertEqual(category['api_url'], reverse('api-part-category-list')) + self.assertEqual(category['help_text'], 'Part category') + + def test_category(self): + """ + Test the PartCategory API OPTIONS endpoint + """ + + actions = self.getActions(reverse('api-part-category-list')) + + # actions should *not* contain 'POST' as we do not have the correct role + self.assertFalse('POST' in actions) + + self.assignRole('part_category.add') + + actions = self.getActions(reverse('api-part-category-list'))['POST'] + + name = actions['name'] + + self.assertTrue(name['required']) + self.assertEqual(name['label'], 'Name') + + loc = actions['default_location'] + self.assertEqual(loc['api_url'], reverse('api-location-list')) + + def test_bom_item(self): + """ + Test the BomItem API OPTIONS endpoint + """ + + actions = self.getActions(reverse('api-bom-list'))['POST'] + + inherited = actions['inherited'] + + self.assertEqual(inherited['type'], 'boolean') + + # 'part' reference + part = actions['part'] + + self.assertTrue(part['required']) + self.assertFalse(part['read_only']) + self.assertTrue(part['filters']['assembly']) + + # 'sub_part' reference + sub_part = actions['sub_part'] + + self.assertTrue(sub_part['required']) + self.assertEqual(sub_part['type'], 'related field') + self.assertTrue(sub_part['filters']['component']) class PartAPITest(InvenTreeAPITestCase): @@ -311,6 +412,59 @@ class PartAPITest(InvenTreeAPITestCase): self.assertEqual(len(data['results']), n) + def test_default_values(self): + """ + Tests for 'default' values: + + Ensure that unspecified fields revert to "default" values + (as specified in the model field definition) + """ + + url = reverse('api-part-list') + + response = self.client.post(url, { + 'name': 'all defaults', + 'description': 'my test part', + 'category': 1, + }) + + data = response.data + + # Check that the un-specified fields have used correct default values + self.assertTrue(data['active']) + self.assertFalse(data['virtual']) + + # By default, parts are not purchaseable + self.assertFalse(data['purchaseable']) + + # Set the default 'purchaseable' status to True + InvenTreeSetting.set_setting( + 'PART_PURCHASEABLE', + True, + self.user + ) + + response = self.client.post(url, { + 'name': 'all defaults', + 'description': 'my test part 2', + 'category': 1, + }) + + # Part should now be purchaseable by default + self.assertTrue(response.data['purchaseable']) + + # "default" values should not be used if the value is specified + response = self.client.post(url, { + 'name': 'all defaults', + 'description': 'my test part 2', + 'category': 1, + 'active': False, + 'purchaseable': False, + }) + + self.assertFalse(response.data['active']) + self.assertFalse(response.data['purchaseable']) + class PartDetailTests(InvenTreeAPITestCase): """ @@ -391,7 +545,14 @@ class PartDetailTests(InvenTreeAPITestCase): # Try to remove the part response = self.client.delete(url) - + + # As the part is 'active' we cannot delete it + self.assertEqual(response.status_code, 405) + + # So, let's make it not active + response = self.patch(url, {'active': False}, expected_code=200) + + response = self.client.delete(url) self.assertEqual(response.status_code, 204) # Part count should have reduced @@ -542,8 +703,6 @@ class PartDetailTests(InvenTreeAPITestCase): # And now check that the image has been set p = Part.objects.get(pk=pk) - print("Image:", p.image.file) - class PartAPIAggregationTest(InvenTreeAPITestCase): """ @@ -646,7 +805,7 @@ class PartParameterTest(InvenTreeAPITestCase): Test for listing part parameters """ - url = reverse('api-part-param-list') + url = reverse('api-part-parameter-list') response = self.client.get(url, format='json') @@ -679,7 +838,7 @@ class PartParameterTest(InvenTreeAPITestCase): Test that we can create a param via the API """ - url = reverse('api-part-param-list') + url = reverse('api-part-parameter-list') response = self.client.post( url, @@ -701,7 +860,7 @@ class PartParameterTest(InvenTreeAPITestCase): Tests for the PartParameter detail endpoint """ - url = reverse('api-part-param-detail', kwargs={'pk': 5}) + url = reverse('api-part-parameter-detail', kwargs={'pk': 5}) response = self.client.get(url) diff --git a/InvenTree/part/test_bom_export.py b/InvenTree/part/test_bom_export.py new file mode 100644 index 0000000000..13ec3a179e --- /dev/null +++ b/InvenTree/part/test_bom_export.py @@ -0,0 +1,131 @@ +""" +Unit testing for BOM export functionality +""" + +from django.test import TestCase + +from django.urls import reverse +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group + + +class BomExportTest(TestCase): + + fixtures = [ + 'category', + 'part', + 'location', + 'bom', + ] + + def setUp(self): + super().setUp() + + # Create a user + user = get_user_model() + + self.user = user.objects.create_user( + username='username', + email='user@email.com', + password='password' + ) + + # Put the user into a group with the correct permissions + group = Group.objects.create(name='mygroup') + self.user.groups.add(group) + + # Give the group *all* the permissions! + for rule in group.rule_sets.all(): + rule.can_view = True + rule.can_change = True + rule.can_add = True + rule.can_delete = True + + rule.save() + + self.client.login(username='username', password='password') + + self.url = reverse('bom-download', kwargs={'pk': 100}) + + def test_export_csv(self): + """ + Test BOM download in CSV format + """ + + print("URL", self.url) + + params = { + 'file_format': 'csv', + 'cascade': True, + 'parameter_data': True, + 'stock_data': True, + 'supplier_data': True, + 'manufacturer_data': True, + } + + response = self.client.get(self.url, data=params) + + self.assertEqual(response.status_code, 200) + + content = response.headers['Content-Disposition'] + self.assertEqual(content, 'attachment; filename="BOB | Bob | A2_BOM.csv"') + + def test_export_xls(self): + """ + Test BOM download in XLS format + """ + + params = { + 'file_format': 'xls', + 'cascade': True, + 'parameter_data': True, + 'stock_data': True, + 'supplier_data': True, + 'manufacturer_data': True, + } + + response = self.client.get(self.url, data=params) + + self.assertEqual(response.status_code, 200) + + content = response.headers['Content-Disposition'] + self.assertEqual(content, 'attachment; filename="BOB | Bob | A2_BOM.xls"') + + def test_export_xlsx(self): + """ + Test BOM download in XLSX format + """ + + params = { + 'file_format': 'xlsx', + 'cascade': True, + 'parameter_data': True, + 'stock_data': True, + 'supplier_data': True, + 'manufacturer_data': True, + } + + response = self.client.get(self.url, data=params) + + self.assertEqual(response.status_code, 200) + + def test_export_json(self): + """ + Test BOM download in JSON format + """ + + params = { + 'file_format': 'json', + 'cascade': True, + 'parameter_data': True, + 'stock_data': True, + 'supplier_data': True, + 'manufacturer_data': True, + } + + response = self.client.get(self.url, data=params) + + self.assertEqual(response.status_code, 200) + + content = response.headers['Content-Disposition'] + self.assertEqual(content, 'attachment; filename="BOB | Bob | A2_BOM.json"') diff --git a/InvenTree/part/test_views.py b/InvenTree/part/test_views.py index c32753cbbb..9779aac544 100644 --- a/InvenTree/part/test_views.py +++ b/InvenTree/part/test_views.py @@ -158,21 +158,6 @@ class PartDetailTest(PartViewTestCase): class PartTests(PartViewTestCase): """ Tests for Part forms """ - def test_part_edit(self): - - response = self.client.get(reverse('part-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - - keys = response.context.keys() - data = str(response.content) - - self.assertEqual(response.status_code, 200) - - self.assertIn('part', keys) - self.assertIn('csrf_token', keys) - - self.assertIn('html_form', data) - self.assertIn('"title":', data) - def test_part_create(self): """ Launch form to create a new part """ response = self.client.get(reverse('part-create'), {'category': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') @@ -232,29 +217,6 @@ class PartRelatedTests(PartViewTestCase): self.assertEqual(n, 1) -class PartAttachmentTests(PartViewTestCase): - - def test_valid_create(self): - """ test creation of an attachment for a valid part """ - - response = self.client.get(reverse('part-attachment-create'), {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # TODO - Create a new attachment using this view - - def test_invalid_create(self): - """ test creation of an attachment for an invalid part """ - - # TODO - pass - - def test_edit(self): - """ test editing an attachment """ - - # TODO - pass - - class PartQRTest(PartViewTestCase): """ Tests for the Part QR Code AJAX view """ @@ -294,11 +256,6 @@ class CategoryTest(PartViewTestCase): # Form should still return OK self.assertEqual(response.status_code, 200) - def test_edit(self): - """ Retrieve the part category editing form """ - response = self.client.get(reverse('category-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - def test_set_category(self): """ Test that the "SetCategory" view works """ diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index d12612c604..2215e14785 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -17,12 +17,6 @@ part_related_urls = [ url(r'^(?P\d+)/delete/?', views.PartRelatedDelete.as_view(), name='part-related-delete'), ] -part_attachment_urls = [ - url(r'^new/?', views.PartAttachmentCreate.as_view(), name='part-attachment-create'), - url(r'^(?P\d+)/edit/?', views.PartAttachmentEdit.as_view(), name='part-attachment-edit'), - url(r'^(?P\d+)/delete/?', views.PartAttachmentDelete.as_view(), name='part-attachment-delete'), -] - sale_price_break_urls = [ url(r'^new/', views.PartSalePriceBreakCreate.as_view(), name='sale-price-break-create'), url(r'^(?P\d+)/edit/', views.PartSalePriceBreakEdit.as_view(), name='sale-price-break-edit'), @@ -39,14 +33,9 @@ part_parameter_urls = [ url(r'^template/new/', views.PartParameterTemplateCreate.as_view(), name='part-param-template-create'), url(r'^template/(?P\d+)/edit/', views.PartParameterTemplateEdit.as_view(), name='part-param-template-edit'), url(r'^template/(?P\d+)/delete/', views.PartParameterTemplateDelete.as_view(), name='part-param-template-edit'), - - url(r'^new/', views.PartParameterCreate.as_view(), name='part-param-create'), - url(r'^(?P\d+)/edit/', views.PartParameterEdit.as_view(), name='part-param-edit'), - url(r'^(?P\d+)/delete/', views.PartParameterDelete.as_view(), name='part-param-delete'), ] part_detail_urls = [ - url(r'^edit/?', views.PartEdit.as_view(), name='part-edit'), url(r'^delete/?', views.PartDelete.as_view(), name='part-delete'), url(r'^bom-export/?', views.BomExport.as_view(), name='bom-export'), url(r'^bom-download/?', views.BomDownload.as_view(), name='bom-download'), @@ -58,30 +47,9 @@ part_detail_urls = [ url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'), url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'), - url(r'^params/', views.PartDetail.as_view(template_name='part/params.html'), name='part-params'), - url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'), - url(r'^stock/?', views.PartDetail.as_view(template_name='part/stock.html'), name='part-stock'), - url(r'^allocation/?', views.PartDetail.as_view(template_name='part/allocation.html'), name='part-allocation'), - url(r'^bom/?', views.PartDetail.as_view(template_name='part/bom.html'), name='part-bom'), - url(r'^build/?', views.PartDetail.as_view(template_name='part/build.html'), name='part-build'), - url(r'^used/?', views.PartDetail.as_view(template_name='part/used_in.html'), name='part-used-in'), - url(r'^order-prices/', views.PartPricingView.as_view(template_name='part/order_prices.html'), name='part-order-prices'), - url(r'^manufacturers/?', views.PartDetail.as_view(template_name='part/manufacturer.html'), name='part-manufacturers'), - url(r'^suppliers/?', views.PartDetail.as_view(template_name='part/supplier.html'), name='part-suppliers'), - url(r'^orders/?', views.PartDetail.as_view(template_name='part/orders.html'), name='part-orders'), - url(r'^sales-orders/', views.PartDetail.as_view(template_name='part/sales_orders.html'), name='part-sales-orders'), - url(r'^sale-prices/', views.PartDetail.as_view(template_name='part/sale_prices.html'), name='part-sale-prices'), - url(r'^internal-prices/', views.PartDetail.as_view(template_name='part/internal_prices.html'), name='part-internal-prices'), - url(r'^tests/', views.PartDetail.as_view(template_name='part/part_tests.html'), name='part-test-templates'), - url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), - url(r'^related-parts/?', views.PartDetail.as_view(template_name='part/related.html'), name='part-related'), - url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), - url(r'^notes/?', views.PartNotes.as_view(), name='part-notes'), - url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), # Normal thumbnail with form - url(r'^thumbnail/?', views.PartImageUpload.as_view(), name='part-image-upload'), url(r'^thumb-select/?', views.PartImageSelect.as_view(), name='part-image-select'), url(r'^thumb-download/', views.PartImageDownloadFromURL.as_view(), name='part-image-download'), @@ -105,13 +73,9 @@ category_urls = [ # Category detail views url(r'(?P\d+)/', include([ - url(r'^edit/', views.CategoryEdit.as_view(), name='category-edit'), url(r'^delete/', views.CategoryDelete.as_view(), name='category-delete'), url(r'^parameters/', include(category_parameter_urls)), - url(r'^subcategory/', views.CategoryDetail.as_view(template_name='part/subcategory.html'), name='category-subcategory'), - url(r'^parametric/', views.CategoryParametric.as_view(), name='category-parametric'), - # Anything else url(r'^.*$', views.CategoryDetail.as_view(), name='category-detail'), ])) @@ -119,7 +83,6 @@ category_urls = [ part_bom_urls = [ url(r'^edit/?', views.BomItemEdit.as_view(), name='bom-item-edit'), - url('^delete/?', views.BomItemDelete.as_view(), name='bom-item-delete'), ] # URL list for part web interface @@ -128,6 +91,10 @@ part_urls = [ # Create a new part url(r'^new/?', views.PartCreate.as_view(), name='part-create'), + # Upload a part + url(r'^import/', views.PartImport.as_view(), name='part-import'), + url(r'^import-api/', views.PartImportAjax.as_view(), name='api-part-import'), + # Create a new BOM item url(r'^bom/new/?', views.BomItemCreate.as_view(), name='bom-item-create'), @@ -146,22 +113,12 @@ part_urls = [ # Part related url(r'^related-parts/', include(part_related_urls)), - # Part attachments - url(r'^attachment/', include(part_attachment_urls)), - # Part price breaks url(r'^sale-price/', include(sale_price_break_urls)), # Part internal price breaks url(r'^internal-price/', include(internal_price_break_urls)), - # Part test templates - url(r'^test-template/', include([ - url(r'^new/', views.PartTestTemplateCreate.as_view(), name='part-test-template-create'), - url(r'^(?P\d+)/edit/', views.PartTestTemplateEdit.as_view(), name='part-test-template-edit'), - url(r'^(?P\d+)/delete/', views.PartTestTemplateDelete.as_view(), name='part-test-template-delete'), - ])), - # Part parameters url(r'^parameter/', include(part_parameter_urls)), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 39e0f13b45..fb69241a10 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -13,10 +13,11 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import HttpResponseRedirect from django.utils.translation import gettext_lazy as _ from django.urls import reverse, reverse_lazy -from django.views.generic import DetailView, ListView, FormView, UpdateView +from django.views.generic import DetailView, ListView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput from django.conf import settings +from django.contrib import messages from moneyed import CURRENCIES from djmoney.contrib.exchange.models import convert_money @@ -30,21 +31,26 @@ import io from rapidfuzz import fuzz from decimal import Decimal, InvalidOperation -from .models import PartCategory, Part, PartAttachment, PartRelated -from .models import PartParameterTemplate, PartParameter +from .models import PartCategory, Part, PartRelated +from .models import PartParameterTemplate from .models import PartCategoryParameterTemplate from .models import BomItem from .models import match_part_names -from .models import PartTestTemplate from .models import PartSellPriceBreak, PartInternalPriceBreak from common.models import InvenTreeSetting from company.models import SupplierPart +from common.files import FileManager +from common.views import FileManagementFormView, FileManagementAjaxView +from common.forms import UploadFileForm, MatchFieldForm + +from stock.models import StockItem, StockLocation import common.settings as inventree_settings from . import forms as part_forms -from .bom import MakeBomTemplate, BomUploadManager, ExportBom, IsValidBOMFormat +from .bom import MakeBomTemplate, ExportBom, IsValidBOMFormat +from order.models import PurchaseOrderLineItem from .admin import PartResource @@ -149,146 +155,6 @@ class PartRelatedDelete(AjaxDeleteView): role_required = 'part.change' -class PartAttachmentCreate(AjaxCreateView): - """ View for creating a new PartAttachment object - - - The view only makes sense if a Part object is passed to it - """ - model = PartAttachment - form_class = part_forms.EditPartAttachmentForm - ajax_form_title = _("Add part attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - """ - Record the user that uploaded this attachment - """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _('Added attachment') - } - - def get_initial(self): - """ Get initial data for new PartAttachment object. - - - Client should have requested this form with a parent part in mind - - e.g. ?part= - """ - - initials = super(AjaxCreateView, self).get_initial() - - # TODO - If the proper part was not sent, return an error message - try: - initials['part'] = Part.objects.get(id=self.request.GET.get('part', None)) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - def get_form(self): - """ Create a form to upload a new PartAttachment - - - Hide the 'part' field - """ - - form = super(AjaxCreateView, self).get_form() - - form.fields['part'].widget = HiddenInput() - - return form - - -class PartAttachmentEdit(AjaxUpdateView): - """ View for editing a PartAttachment object """ - - model = PartAttachment - form_class = part_forms.EditPartAttachmentForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit attachment') - - def get_data(self): - return { - 'success': _('Part attachment updated') - } - - def get_form(self): - form = super(AjaxUpdateView, self).get_form() - - form.fields['part'].widget = HiddenInput() - - return form - - -class PartAttachmentDelete(AjaxDeleteView): - """ View for deleting a PartAttachment """ - - model = PartAttachment - ajax_form_title = _("Delete Part Attachment") - ajax_template_name = "attachment_delete.html" - context_object_name = "attachment" - - role_required = 'part.change' - - def get_data(self): - return { - 'danger': _('Deleted part attachment') - } - - -class PartTestTemplateCreate(AjaxCreateView): - """ View for creating a PartTestTemplate """ - - model = PartTestTemplate - form_class = part_forms.EditPartTestTemplateForm - ajax_form_title = _("Create Test Template") - - def get_initial(self): - - initials = super().get_initial() - - try: - part_id = self.request.GET.get('part', None) - initials['part'] = Part.objects.get(pk=part_id) - except (ValueError, Part.DoesNotExist): - pass - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PartTestTemplateEdit(AjaxUpdateView): - """ View for editing a PartTestTemplate """ - - model = PartTestTemplate - form_class = part_forms.EditPartTestTemplateForm - ajax_form_title = _("Edit Test Template") - - def get_form(self): - - form = super().get_form() - form.fields['part'].widget = HiddenInput() - - return form - - -class PartTestTemplateDelete(AjaxDeleteView): - """ View for deleting a PartTestTemplate """ - - model = PartTestTemplate - ajax_form_title = _("Delete Test Template") - - class PartSetCategory(AjaxUpdateView): """ View for settings the part category for multiple parts at once """ @@ -621,6 +487,10 @@ class PartCreate(AjaxCreateView): if not inventree_settings.stock_expiry_enabled(): form.fields['default_expiry'].widget = HiddenInput() + # Hide the "initial stock amount" field if the feature is not enabled + if not InvenTreeSetting.get_setting('PART_CREATE_INITIAL'): + form.fields['initial_stock'].widget = HiddenInput() + # Hide the default_supplier field (there are no matching supplier parts yet!) form.fields['default_supplier'].widget = HiddenInput() @@ -681,6 +551,14 @@ class PartCreate(AjaxCreateView): # Save part and pass category template settings part.save(**{'add_category_templates': add_category_templates}) + # Add stock if set + init_stock = int(request.POST.get('initial_stock', 0)) + if init_stock: + stock = StockItem(part=part, + quantity=init_stock, + location=part.default_location) + stock.save() + data['pk'] = part.pk data['text'] = str(part) @@ -719,38 +597,166 @@ class PartCreate(AjaxCreateView): return initials -class PartNotes(UpdateView): - """ View for editing the 'notes' field of a Part object. - Presents a live markdown editor. - """ +class PartImport(FileManagementFormView): + ''' Part: Upload file, match to fields and import parts(using multi-Step form) ''' + permission_required = 'part.add' - context_object_name = 'part' - # form_class = part_forms.EditNotesForm - template_name = 'part/notes.html' - model = Part + class PartFileManager(FileManager): + REQUIRED_HEADERS = [ + 'Name', + 'Description', + ] - role_required = 'part.change' + OPTIONAL_MATCH_HEADERS = [ + 'Category', + 'default_location', + 'default_supplier', + ] - fields = ['notes'] + OPTIONAL_HEADERS = [ + 'Keywords', + 'IPN', + 'Revision', + 'Link', + 'default_expiry', + 'minimum_stock', + 'Units', + 'Notes', + ] - def get_success_url(self): - """ Return the success URL for this form """ + name = 'part' + form_steps_template = [ + 'part/import_wizard/part_upload.html', + 'part/import_wizard/match_fields.html', + 'part/import_wizard/match_references.html', + ] + form_steps_description = [ + _("Upload File"), + _("Match Fields"), + _("Match References"), + ] - return reverse('part-notes', kwargs={'pk': self.get_object().id}) + form_field_map = { + 'name': 'name', + 'description': 'description', + 'keywords': 'keywords', + 'ipn': 'ipn', + 'revision': 'revision', + 'link': 'link', + 'default_expiry': 'default_expiry', + 'minimum_stock': 'minimum_stock', + 'units': 'units', + 'notes': 'notes', + 'category': 'category', + 'default_location': 'default_location', + 'default_supplier': 'default_supplier', + } + file_manager_class = PartFileManager - def get_context_data(self, **kwargs): + def get_field_selection(self): + """ Fill the form fields for step 3 """ + # fetch available elements + self.allowed_items = {} + self.matches = {} - part = self.get_object() + self.allowed_items['Category'] = PartCategory.objects.all() + self.matches['Category'] = ['name__contains'] + self.allowed_items['default_location'] = StockLocation.objects.all() + self.matches['default_location'] = ['name__contains'] + self.allowed_items['default_supplier'] = SupplierPart.objects.all() + self.matches['default_supplier'] = ['SKU__contains'] - context = super().get_context_data(**kwargs) + # setup + self.file_manager.setup() + # collect submitted column indexes + col_ids = {} + for col in self.file_manager.HEADERS: + index = self.get_column_index(col) + if index >= 0: + col_ids[col] = index - context['editing'] = str2bool(self.request.GET.get('edit', '')) + # parse all rows + for row in self.rows: + # check each submitted column + for idx in col_ids: + data = row['data'][col_ids[idx]]['cell'] - ctx = part.get_context_data(self.request) + if idx in self.file_manager.OPTIONAL_MATCH_HEADERS: + try: + exact_match = self.allowed_items[idx].get(**{a: data for a in self.matches[idx]}) + except (ValueError, self.allowed_items[idx].model.DoesNotExist, self.allowed_items[idx].model.MultipleObjectsReturned): + exact_match = None - context.update(ctx) + row['match_options_' + idx] = self.allowed_items[idx] + row['match_' + idx] = exact_match + continue - return context + # general fields + row[idx.lower()] = data + + def done(self, form_list, **kwargs): + """ Create items """ + items = self.get_clean_items() + + import_done = 0 + import_error = [] + + # Create Part instances + for part_data in items.values(): + + # set related parts + optional_matches = {} + for idx in self.file_manager.OPTIONAL_MATCH_HEADERS: + if idx.lower() in part_data: + try: + optional_matches[idx] = self.allowed_items[idx].get(pk=int(part_data[idx.lower()])) + except (ValueError, self.allowed_items[idx].model.DoesNotExist, self.allowed_items[idx].model.MultipleObjectsReturned): + optional_matches[idx] = None + else: + optional_matches[idx] = None + + # add part + new_part = Part( + name=part_data.get('name', ''), + description=part_data.get('description', ''), + keywords=part_data.get('keywords', None), + IPN=part_data.get('ipn', None), + revision=part_data.get('revision', None), + link=part_data.get('link', None), + default_expiry=part_data.get('default_expiry', 0), + minimum_stock=part_data.get('minimum_stock', 0), + units=part_data.get('units', None), + notes=part_data.get('notes', None), + category=optional_matches['Category'], + default_location=optional_matches['default_location'], + default_supplier=optional_matches['default_supplier'], + ) + try: + new_part.save() + import_done += 1 + except ValidationError as _e: + import_error.append(', '.join(set(_e.messages))) + + # Set alerts + if import_done: + alert = f"{_('Part-Import')}
                {_('Imported {n} parts').format(n=import_done)}" + messages.success(self.request, alert) + if import_error: + error_text = '\n'.join([f'
              • x{import_error.count(a)}: {a}
              • ' for a in set(import_error)]) + messages.error(self.request, f"{_('Some errors occured:')}
                  {error_text}
                ") + + return HttpResponseRedirect(reverse('part-index')) + + +class PartImportAjax(FileManagementAjaxView, PartImport): + ajax_form_steps_template = [ + 'part/import_wizard/ajax_part_upload.html', + 'part/import_wizard/ajax_match_fields.html', + 'part/import_wizard/ajax_match_references.html', + ] + + def validate(self, obj, form, **kwargs): + return PartImport.validate(self, self.steps.current, form, **kwargs) class PartDetail(InvenTreeRoleMixin, DetailView): @@ -760,6 +766,7 @@ class PartDetail(InvenTreeRoleMixin, DetailView): context_object_name = 'part' queryset = Part.objects.all().select_related('category') template_name = 'part/detail.html' + form_class = part_forms.PartPriceForm # Add in some extra context information based on query params def get_context_data(self, **kwargs): @@ -780,25 +787,12 @@ class PartDetail(InvenTreeRoleMixin, DetailView): ctx = part.get_context_data(self.request) context.update(**ctx) - return context - - -class PartPricingView(PartDetail): - """ Detail view for Part object - """ - context_object_name = 'part' - template_name = 'part/order_prices.html' - form_class = part_forms.PartPriceForm - - # Add in some extra context information based on query params - def get_context_data(self, **kwargs): - """ Provide extra context data to template """ - context = super().get_context_data(**kwargs) - + # Pricing information ctx = self.get_pricing(self.get_quantity()) ctx['form'] = self.form_class(initial=self.get_initials()) context.update(ctx) + return context def get_quantity(self): @@ -812,18 +806,20 @@ class PartPricingView(PartDetail): """ returns context with pricing information """ ctx = PartPricing.get_pricing(self, quantity, currency) part = self.get_part() + default_currency = inventree_settings.currency_code_default() + # Stock history if part.total_stock > 1: price_history = [] - stock = part.stock_entries(include_variants=False, in_stock=True) # .order_by('purchase_order__date') - stock = stock.prefetch_related('purchase_order', 'supplier_part') + stock = part.stock_entries(include_variants=False, in_stock=True).\ + order_by('purchase_order__issue_date').prefetch_related('purchase_order', 'supplier_part') for stock_item in stock: if None in [stock_item.purchase_price, stock_item.quantity]: continue # convert purchase price to current currency - only one currency in the graph - price = convert_money(stock_item.purchase_price, inventree_settings.currency_code_default()) + price = convert_money(stock_item.purchase_price, default_currency) line = { 'price': price.amount, 'qty': stock_item.quantity @@ -847,11 +843,13 @@ class PartPricingView(PartDetail): # BOM Information for Pie-Chart if part.has_bom: + # get internal price setting + use_internal = InvenTreeSetting.get_setting('PART_BOM_USE_INTERNAL_PRICE', False) ctx_bom_parts = [] # iterate over all bom-items for item in part.bom_items.all(): ctx_item = {'name': str(item.sub_part)} - price, qty = item.sub_part.get_price_range(quantity), item.quantity + price, qty = item.sub_part.get_price_range(quantity, internal=use_internal), item.quantity price_min, price_max = 0, 0 if price: # check if price available @@ -867,6 +865,36 @@ class PartPricingView(PartDetail): # add to global context ctx['bom_parts'] = ctx_bom_parts + # Sale price history + sale_items = PurchaseOrderLineItem.objects.filter(part__part=part).order_by('order__issue_date').\ + prefetch_related('order', ).all() + + if sale_items: + sale_history = [] + + for sale_item in sale_items: + # check for not fully defined elements + if None in [sale_item.purchase_price, sale_item.quantity]: + continue + + price = convert_money(sale_item.purchase_price, default_currency) + line = { + 'price': price.amount if price else 0, + 'qty': sale_item.quantity, + } + + # set date for graph labels + if sale_item.order.issue_date: + line['date'] = sale_item.order.issue_date.strftime('%d.%m.%Y') + elif sale_item.order.creation_date: + line['date'] = sale_item.order.creation_date.strftime('%d.%m.%Y') + else: + line['date'] = _('None') + + sale_history.append(line) + + ctx['sale_history'] = sale_history + return ctx def get_initials(self): @@ -1017,21 +1045,6 @@ class PartImageDownloadFromURL(AjaxUpdateView): ) -class PartImageUpload(AjaxUpdateView): - """ View for uploading a new Part image """ - - model = Part - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Upload Part Image') - - form_class = part_forms.PartImageForm - - def get_data(self): - return { - 'success': _('Updated part image'), - } - - class PartImageSelect(AjaxUpdateView): """ View for selecting Part image from existing images. """ @@ -1071,40 +1084,6 @@ class PartImageSelect(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class PartEdit(AjaxUpdateView): - """ View for editing Part object """ - - model = Part - form_class = part_forms.EditPartForm - ajax_template_name = 'modal_form.html' - ajax_form_title = _('Edit Part Properties') - context_object_name = 'part' - - def get_form(self): - """ Create form for Part editing. - Overrides default get_form() method to limit the choices - for the 'default_supplier' field to SupplierParts that reference this part - """ - - form = super(AjaxUpdateView, self).get_form() - - # Hide the "default expiry" field if the feature is not enabled - if not inventree_settings.stock_expiry_enabled(): - form.fields['default_expiry'].widget = HiddenInput() - - part = self.get_object() - - form.fields['default_supplier'].queryset = SupplierPart.objects.filter(part=part) - - # Check if IPN can be edited - ipn_edit_enable = InvenTreeSetting.get_setting('PART_ALLOW_EDIT_IPN') - if not ipn_edit_enable and not self.request.user.is_superuser: - # Admin can still change IPN - form.fields['IPN'].disabled = True - - return form - - class BomDuplicate(AjaxUpdateView): """ View for duplicating BOM from a parent item. @@ -1199,7 +1178,7 @@ class BomValidate(AjaxUpdateView): } -class BomUpload(InvenTreeRoleMixin, FormView): +class BomUpload(InvenTreeRoleMixin, FileManagementFormView): """ View for uploading a BOM file, and handling BOM data importing. The BOM upload process is as follows: @@ -1226,184 +1205,116 @@ class BomUpload(InvenTreeRoleMixin, FormView): During these steps, data are passed between the server/client as JSON objects. """ - template_name = 'part/bom_upload/upload_file.html' - - # Context data passed to the forms (initially empty, extracted from uploaded file) - bom_headers = [] - bom_columns = [] - bom_rows = [] - missing_columns = [] - allowed_parts = [] - role_required = ('part.change', 'part.add') - def get_success_url(self): - part = self.get_object() - return reverse('upload-bom', kwargs={'pk': part.id}) + class BomFileManager(FileManager): + # Fields which are absolutely necessary for valid upload + REQUIRED_HEADERS = [ + 'Quantity' + ] - def get_form_class(self): + # Fields which are used for part matching (only one of them is needed) + ITEM_MATCH_HEADERS = [ + 'Part_Name', + 'Part_IPN', + 'Part_ID', + ] - # Default form is the starting point - return part_forms.BomUploadSelectFile + # Fields which would be helpful but are not required + OPTIONAL_HEADERS = [ + 'Reference', + 'Note', + 'Overage', + ] - def get_context_data(self, *args, **kwargs): + EDITABLE_HEADERS = [ + 'Reference', + 'Note', + 'Overage' + ] - ctx = super().get_context_data(*args, **kwargs) + name = 'order' + form_list = [ + ('upload', UploadFileForm), + ('fields', MatchFieldForm), + ('items', part_forms.BomMatchItemForm), + ] + form_steps_template = [ + 'part/bom_upload/upload_file.html', + 'part/bom_upload/match_fields.html', + 'part/bom_upload/match_parts.html', + ] + form_steps_description = [ + _("Upload File"), + _("Match Fields"), + _("Match Parts"), + ] + form_field_map = { + 'item_select': 'part', + 'quantity': 'quantity', + 'overage': 'overage', + 'reference': 'reference', + 'note': 'note', + } + file_manager_class = BomFileManager - # Give each row item access to the column it is in - # This provides for much simpler template rendering + def get_part(self): + """ Get part or return 404 """ - rows = [] - for row in self.bom_rows: - row_data = row['data'] + return get_object_or_404(Part, pk=self.kwargs['pk']) - data = [] + def get_context_data(self, form, **kwargs): + """ Handle context data for order """ - for idx, item in enumerate(row_data): + context = super().get_context_data(form=form, **kwargs) - data.append({ - 'cell': item, - 'idx': idx, - 'column': self.bom_columns[idx] - }) + part = self.get_part() - rows.append({ - 'index': row.get('index', -1), - 'data': data, - 'part_match': row.get('part_match', None), - 'part_options': row.get('part_options', self.allowed_parts), + context.update({'part': part}) - # User-input (passed between client and server) - 'quantity': row.get('quantity', None), - 'description': row.get('description', ''), - 'part_name': row.get('part_name', ''), - 'part': row.get('part', None), - 'reference': row.get('reference', ''), - 'notes': row.get('notes', ''), - 'errors': row.get('errors', ''), - }) + return context - ctx['part'] = self.part - ctx['bom_headers'] = BomUploadManager.HEADERS - ctx['bom_columns'] = self.bom_columns - ctx['bom_rows'] = rows - ctx['missing_columns'] = self.missing_columns - ctx['allowed_parts_list'] = self.allowed_parts - - return ctx - - def getAllowedParts(self): + def get_allowed_parts(self): """ Return a queryset of parts which are allowed to be added to this BOM. """ - return self.part.get_allowed_bom_items() + return self.get_part().get_allowed_bom_items() - def get(self, request, *args, **kwargs): - """ Perform the initial 'GET' request. - - Initially returns a form for file upload """ - - self.request = request - - # A valid Part object must be supplied. This is the 'parent' part for the BOM - self.part = get_object_or_404(Part, pk=self.kwargs['pk']) - - self.form = self.get_form() - - form_class = self.get_form_class() - form = self.get_form(form_class) - return self.render_to_response(self.get_context_data(form=form)) - - def handleBomFileUpload(self): - """ Process a BOM file upload form. - - This function validates that the uploaded file was valid, - and contains tabulated data that can be extracted. - If the file does not satisfy these requirements, - the "upload file" form is again shown to the user. - """ - - bom_file = self.request.FILES.get('bom_file', None) - - manager = None - bom_file_valid = False - - if bom_file is None: - self.form.add_error('bom_file', _('No BOM file provided')) - else: - # Create a BomUploadManager object - will perform initial data validation - # (and raise a ValidationError if there is something wrong with the file) - try: - manager = BomUploadManager(bom_file) - bom_file_valid = True - except ValidationError as e: - errors = e.error_dict - - for k, v in errors.items(): - self.form.add_error(k, v) - - if bom_file_valid: - # BOM file is valid? Proceed to the next step! - form = None - self.template_name = 'part/bom_upload/select_fields.html' - - self.extractDataFromFile(manager) - else: - form = self.form - - return self.render_to_response(self.get_context_data(form=form)) - - def getColumnIndex(self, name): - """ Return the index of the column with the given name. - It named column is not found, return -1 - """ - - try: - idx = list(self.column_selections.values()).index(name) - except ValueError: - idx = -1 - - return idx - - def preFillSelections(self): + def get_field_selection(self): """ Once data columns have been selected, attempt to pre-select the proper data from the database. This function is called once the field selection has been validated. The pre-fill data are then passed through to the part selection form. """ + self.allowed_items = self.get_allowed_parts() + # Fields prefixed with "Part_" can be used to do "smart matching" against Part objects in the database - k_idx = self.getColumnIndex('Part_ID') - p_idx = self.getColumnIndex('Part_Name') - i_idx = self.getColumnIndex('Part_IPN') + k_idx = self.get_column_index('Part_ID') + p_idx = self.get_column_index('Part_Name') + i_idx = self.get_column_index('Part_IPN') - q_idx = self.getColumnIndex('Quantity') - r_idx = self.getColumnIndex('Reference') - o_idx = self.getColumnIndex('Overage') - n_idx = self.getColumnIndex('Note') + q_idx = self.get_column_index('Quantity') + r_idx = self.get_column_index('Reference') + o_idx = self.get_column_index('Overage') + n_idx = self.get_column_index('Note') - for row in self.bom_rows: + for row in self.rows: """ - Iterate through each row in the uploaded data, and see if we can match the row to a "Part" object in the database. - There are three potential ways to match, based on the uploaded data: - a) Use the PK (primary key) field for the part, uploaded in the "Part_ID" field b) Use the IPN (internal part number) field for the part, uploaded in the "Part_IPN" field c) Use the name of the part, uploaded in the "Part_Name" field - Notes: - If using the Part_ID field, we can do an exact match against the PK field - If using the Part_IPN field, we can do an exact match against the IPN field - If using the Part_Name field, we can use fuzzy string matching to match "close" values - We also extract other information from the row, for the other non-matched fields: - Quantity - Reference - Overage - Note - """ # Initially use a quantity of zero @@ -1413,42 +1324,55 @@ class BomUpload(InvenTreeRoleMixin, FormView): exact_match_part = None # A list of potential Part matches - part_options = self.allowed_parts + part_options = self.allowed_items # Check if there is a column corresponding to "quantity" if q_idx >= 0: - q_val = row['data'][q_idx] + q_val = row['data'][q_idx]['cell'] if q_val: + # Delete commas + q_val = q_val.replace(',', '') + try: # Attempt to extract a valid quantity from the field quantity = Decimal(q_val) + # Store the 'quantity' value + row['quantity'] = quantity except (ValueError, InvalidOperation): pass - # Store the 'quantity' value - row['quantity'] = quantity - # Check if there is a column corresponding to "PK" if k_idx >= 0: - pk = row['data'][k_idx] + pk = row['data'][k_idx]['cell'] if pk: try: # Attempt Part lookup based on PK value - exact_match_part = Part.objects.get(pk=pk) + exact_match_part = self.allowed_items.get(pk=pk) except (ValueError, Part.DoesNotExist): exact_match_part = None - # Check if there is a column corresponding to "Part Name" - if p_idx >= 0: - part_name = row['data'][p_idx] + # Check if there is a column corresponding to "Part IPN" and no exact match found yet + if i_idx >= 0 and not exact_match_part: + part_ipn = row['data'][i_idx]['cell'] + + if part_ipn: + part_matches = [part for part in self.allowed_items if part.IPN and part_ipn.lower() == str(part.IPN.lower())] + + # Check for single match + if len(part_matches) == 1: + exact_match_part = part_matches[0] + + # Check if there is a column corresponding to "Part Name" and no exact match found yet + if p_idx >= 0 and not exact_match_part: + part_name = row['data'][p_idx]['cell'] row['part_name'] = part_name matches = [] - for part in self.allowed_parts: + for part in self.allowed_items: ratio = fuzz.partial_ratio(part.name + part.description, part_name) matches.append({'part': part, 'match': ratio}) @@ -1457,390 +1381,67 @@ class BomUpload(InvenTreeRoleMixin, FormView): matches = sorted(matches, key=lambda item: item['match'], reverse=True) part_options = [m['part'] for m in matches] + + # Supply list of part options for each row, sorted by how closely they match the part name + row['item_options'] = part_options - # Check if there is a column corresponding to "Part IPN" - if i_idx >= 0: - row['part_ipn'] = row['data'][i_idx] + # Unless found, the 'item_match' is blank + row['item_match'] = None + + if exact_match_part: + # If there is an exact match based on PK or IPN, use that + row['item_match'] = exact_match_part # Check if there is a column corresponding to "Overage" field if o_idx >= 0: - row['overage'] = row['data'][o_idx] + row['overage'] = row['data'][o_idx]['cell'] # Check if there is a column corresponding to "Reference" field if r_idx >= 0: - row['reference'] = row['data'][r_idx] + row['reference'] = row['data'][r_idx]['cell'] # Check if there is a column corresponding to "Note" field if n_idx >= 0: - row['note'] = row['data'][n_idx] - - # Supply list of part options for each row, sorted by how closely they match the part name - row['part_options'] = part_options - - # Unless found, the 'part_match' is blank - row['part_match'] = None - - if exact_match_part: - # If there is an exact match based on PK, use that - row['part_match'] = exact_match_part - else: - # Otherwise, check to see if there is a matching IPN - try: - if row['part_ipn']: - part_matches = [part for part in self.allowed_parts if part.IPN and row['part_ipn'].lower() == str(part.IPN.lower())] - - # Check for single match - if len(part_matches) == 1: - row['part_match'] = part_matches[0] - - continue - except KeyError: - pass - - def extractDataFromFile(self, bom): - """ Read data from the BOM file """ - - self.bom_columns = bom.columns() - self.bom_rows = bom.rows() - - def getTableDataFromPost(self): - """ Extract table cell data from POST request. - These data are used to maintain state between sessions. - - Table data keys are as follows: - - col_name_ - Column name at idx as provided in the uploaded file - col_guess_ - Column guess at idx as selected in the BOM - row__col - Cell data as provided in the uploaded file - - """ - - # Map the columns - self.column_names = {} - self.column_selections = {} - - self.row_data = {} - - for item in self.request.POST: - value = self.request.POST[item] - - # Column names as passed as col_name_ where idx is an integer - - # Extract the column names - if item.startswith('col_name_'): - try: - col_id = int(item.replace('col_name_', '')) - except ValueError: - continue - col_name = value - - self.column_names[col_id] = col_name - - # Extract the column selections (in the 'select fields' view) - if item.startswith('col_guess_'): - - try: - col_id = int(item.replace('col_guess_', '')) - except ValueError: - continue - - col_name = value - - self.column_selections[col_id] = value - - # Extract the row data - if item.startswith('row_'): - # Item should be of the format row__col_ - s = item.split('_') - - if len(s) < 4: - continue - - # Ignore row/col IDs which are not correct numeric values - try: - row_id = int(s[1]) - col_id = int(s[3]) - except ValueError: - continue - - if row_id not in self.row_data: - self.row_data[row_id] = {} - - self.row_data[row_id][col_id] = value - - self.col_ids = sorted(self.column_names.keys()) - - # Re-construct the data table - self.bom_rows = [] - - for row_idx in sorted(self.row_data.keys()): - row = self.row_data[row_idx] - items = [] - - for col_idx in sorted(row.keys()): - - value = row[col_idx] - items.append(value) - - self.bom_rows.append({ - 'index': row_idx, - 'data': items, - 'errors': {}, - }) - - # Construct the column data - self.bom_columns = [] - - # Track any duplicate column selections - self.duplicates = False - - for col in self.col_ids: - - if col in self.column_selections: - guess = self.column_selections[col] - else: - guess = None - - header = ({ - 'name': self.column_names[col], - 'guess': guess - }) - - if guess: - n = list(self.column_selections.values()).count(self.column_selections[col]) - if n > 1: - header['duplicate'] = True - self.duplicates = True - - self.bom_columns.append(header) - - # Are there any missing columns? - self.missing_columns = [] - - # Check that all required fields are present - for col in BomUploadManager.REQUIRED_HEADERS: - if col not in self.column_selections.values(): - self.missing_columns.append(col) - - # Check that at least one of the part match field is present - part_match_found = False - for col in BomUploadManager.PART_MATCH_HEADERS: - if col in self.column_selections.values(): - part_match_found = True - break - - # If not, notify user - if not part_match_found: - for col in BomUploadManager.PART_MATCH_HEADERS: - self.missing_columns.append(col) - - def handleFieldSelection(self): - """ Handle the output of the field selection form. - Here the user is presented with the raw data and must select the - column names and which rows to process. - """ - - # Extract POST data - self.getTableDataFromPost() - - valid = len(self.missing_columns) == 0 and not self.duplicates - - if valid: - # Try to extract meaningful data - self.preFillSelections() - self.template_name = 'part/bom_upload/select_parts.html' - else: - self.template_name = 'part/bom_upload/select_fields.html' - - return self.render_to_response(self.get_context_data(form=None)) - - def handlePartSelection(self): - - # Extract basic table data from POST request - self.getTableDataFromPost() - - # Keep track of the parts that have been selected - parts = {} - - # Extract other data (part selections, etc) - for key in self.request.POST: - value = self.request.POST[key] - - # Extract quantity from each row - if key.startswith('quantity_'): - try: - row_id = int(key.replace('quantity_', '')) - - row = self.getRowByIndex(row_id) - - if row is None: - continue - - q = Decimal(1) - - try: - q = Decimal(value) - if q < 0: - row['errors']['quantity'] = _('Quantity must be greater than zero') - - if 'part' in row.keys(): - if row['part'].trackable: - # Trackable parts must use integer quantities - if not q == int(q): - row['errors']['quantity'] = _('Quantity must be integer value for trackable parts') - - except (ValueError, InvalidOperation): - row['errors']['quantity'] = _('Enter a valid quantity') - - row['quantity'] = q - - except ValueError: - continue - - # Extract part from each row - if key.startswith('part_'): - - try: - row_id = int(key.replace('part_', '')) - - row = self.getRowByIndex(row_id) - - if row is None: - continue - except ValueError: - # Row ID non integer value - continue - - try: - part_id = int(value) - part = Part.objects.get(id=part_id) - except ValueError: - row['errors']['part'] = _('Select valid part') - continue - except Part.DoesNotExist: - row['errors']['part'] = _('Select valid part') - continue - - # Keep track of how many of each part we have seen - if part_id in parts: - parts[part_id]['quantity'] += 1 - row['errors']['part'] = _('Duplicate part selected') - else: - parts[part_id] = { - 'part': part, - 'quantity': 1, - } - - row['part'] = part - - if part.trackable: - # For trackable parts, ensure the quantity is an integer value! - if 'quantity' in row.keys(): - q = row['quantity'] - - if not q == int(q): - row['errors']['quantity'] = _('Quantity must be integer value for trackable parts') - - # Extract other fields which do not require further validation - for field in ['reference', 'notes']: - if key.startswith(field + '_'): - try: - row_id = int(key.replace(field + '_', '')) - - row = self.getRowByIndex(row_id) - - if row: - row[field] = value - except: - continue - - # Are there any errors after form handling? - valid = True - - for row in self.bom_rows: - # Has a part been selected for the given row? - part = row.get('part', None) - - if part is None: - row['errors']['part'] = _('Select a part') - else: - # Will the selected part result in a recursive BOM? - try: - part.checkAddToBOM(self.part) - except ValidationError: - row['errors']['part'] = _('Selected part creates a circular BOM') - - # Has a quantity been specified? - if row.get('quantity', None) is None: - row['errors']['quantity'] = _('Specify quantity') - - errors = row.get('errors', []) - - if len(errors) > 0: - valid = False - - self.template_name = 'part/bom_upload/select_parts.html' - - ctx = self.get_context_data(form=None) - - if valid: - self.part.clear_bom() - - # Generate new BOM items - for row in self.bom_rows: - part = row.get('part') - quantity = row.get('quantity') - reference = row.get('reference', '') - notes = row.get('notes', '') - - # Create a new BOM item! - item = BomItem( - part=self.part, - sub_part=part, - quantity=quantity, - reference=reference, - note=notes - ) - + row['note'] = row['data'][n_idx]['cell'] + + def done(self, form_list, **kwargs): + """ Once all the data is in, process it to add BomItem instances to the part """ + + self.part = self.get_part() + items = self.get_clean_items() + + # Clear BOM + self.part.clear_bom() + + # Generate new BOM items + for bom_item in items.values(): + try: + part = Part.objects.get(pk=int(bom_item.get('part'))) + except (ValueError, Part.DoesNotExist): + continue + + quantity = bom_item.get('quantity') + overage = bom_item.get('overage', '') + reference = bom_item.get('reference', '') + note = bom_item.get('note', '') + + # Create a new BOM item + item = BomItem( + part=self.part, + sub_part=part, + quantity=quantity, + overage=overage, + reference=reference, + note=note, + ) + + try: item.save() + except IntegrityError: + # BomItem already exists + pass - # Redirect to the BOM view - return HttpResponseRedirect(reverse('part-bom', kwargs={'pk': self.part.id})) - else: - ctx['form_errors'] = True - - return self.render_to_response(ctx) - - def getRowByIndex(self, idx): - - for row in self.bom_rows: - if row['index'] == idx: - return row - - return None - - def post(self, request, *args, **kwargs): - """ Perform the various 'POST' requests required. - """ - - self.request = request - - self.part = get_object_or_404(Part, pk=self.kwargs['pk']) - self.allowed_parts = self.getAllowedParts() - self.form = self.get_form(self.get_form_class()) - - # Did the user POST a file named bom_file? - - form_step = request.POST.get('form_step', None) - - if form_step == 'select_file': - return self.handleBomFileUpload() - elif form_step == 'select_fields': - return self.handleFieldSelection() - elif form_step == 'select_parts': - return self.handlePartSelection() - - return self.render_to_response(self.get_context_data(form=self.form)) + return HttpResponseRedirect(reverse('part-detail', kwargs={'pk': self.kwargs['pk']})) class PartExport(AjaxView): @@ -2211,85 +1812,13 @@ class PartParameterTemplateDelete(AjaxDeleteView): ajax_form_title = _("Delete Part Parameter Template") -class PartParameterCreate(AjaxCreateView): - """ View for creating a new PartParameter """ - - model = PartParameter - form_class = part_forms.EditPartParameterForm - ajax_form_title = _('Create Part Parameter') - - def get_initial(self): - - initials = {} - - part_id = self.request.GET.get('part', None) - - if part_id: - try: - initials['part'] = Part.objects.get(pk=part_id) - except (Part.DoesNotExist, ValueError): - pass - - return initials - - def get_form(self): - """ Return the form object. - - - Hide the 'Part' field (specified in URL) - - Limit the 'Template' options (to avoid duplicates) - """ - - form = super().get_form() - - part_id = self.request.GET.get('part', None) - - if part_id: - try: - part = Part.objects.get(pk=part_id) - - form.fields['part'].widget = HiddenInput() - - query = form.fields['template'].queryset - - query = query.exclude(id__in=[param.template.id for param in part.parameters.all()]) - - form.fields['template'].queryset = query - - except (Part.DoesNotExist, ValueError): - pass - - return form - - -class PartParameterEdit(AjaxUpdateView): - """ View for editing a PartParameter """ - - model = PartParameter - form_class = part_forms.EditPartParameterForm - ajax_form_title = _('Edit Part Parameter') - - def get_form(self): - - form = super().get_form() - - return form - - -class PartParameterDelete(AjaxDeleteView): - """ View for deleting a PartParameter """ - - model = PartParameter - ajax_template_name = 'part/param_delete.html' - ajax_form_title = _('Delete Part Parameter') - - class CategoryDetail(InvenTreeRoleMixin, DetailView): """ Detail view for PartCategory """ model = PartCategory context_object_name = 'category' queryset = PartCategory.objects.all().prefetch_related('children') - template_name = 'part/category_partlist.html' + template_name = 'part/category.html' def get_context_data(self, **kwargs): @@ -2300,18 +1829,6 @@ class CategoryDetail(InvenTreeRoleMixin, DetailView): except KeyError: context['part_count'] = 0 - return context - - -class CategoryParametric(CategoryDetail): - """ Parametric view for PartCategory """ - - template_name = 'part/category_parametric.html' - - def get_context_data(self, **kwargs): - - context = super(CategoryParametric, self).get_context_data(**kwargs).copy() - # Get current category category = kwargs.get('object', None) @@ -2732,17 +2249,10 @@ class BomItemEdit(AjaxUpdateView): return form -class BomItemDelete(AjaxDeleteView): - """ Delete view for removing BomItem """ - - model = BomItem - ajax_template_name = 'part/bom-delete.html' - context_object_name = 'item' - ajax_form_title = _('Confim BOM item deletion') - - class PartSalePriceBreakCreate(AjaxCreateView): - """ View for creating a sale price break for a part """ + """ + View for creating a sale price break for a part + """ model = PartSellPriceBreak form_class = part_forms.EditPartSalePriceBreakForm @@ -2780,7 +2290,7 @@ class PartSalePriceBreakCreate(AjaxCreateView): initials['part'] = self.get_part() - default_currency = settings.BASE_CURRENCY + default_currency = inventree_settings.currency_code_default() currency = CURRENCIES.get(default_currency, None) if currency is not None: diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index ecb4d91492..db06e1c95b 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -11,6 +11,7 @@ import logging import datetime +from django.urls import reverse from django.db import models from django.conf import settings from django.core.exceptions import ValidationError, FieldError @@ -307,6 +308,10 @@ class TestReport(ReportTemplateBase): Render a TestReport against a StockItem object. """ + @staticmethod + def get_api_url(): + return reverse('api-stockitem-testreport-list') + @classmethod def getSubdir(cls): return 'test' @@ -352,7 +357,8 @@ class TestReport(ReportTemplateBase): 'serial': stock_item.serial, 'part': stock_item.part, 'results': stock_item.testResultMap(include_installed=self.include_installed), - 'result_list': stock_item.testResultList(include_installed=self.include_installed) + 'result_list': stock_item.testResultList(include_installed=self.include_installed), + 'installed_items': stock_item.get_installed_items(cascade=True), } @@ -361,6 +367,10 @@ class BuildReport(ReportTemplateBase): Build order / work order report """ + @staticmethod + def get_api_url(): + return reverse('api-build-report-list') + @classmethod def getSubdir(cls): return 'build' @@ -400,6 +410,10 @@ class BillOfMaterialsReport(ReportTemplateBase): Render a Bill of Materials against a Part object """ + @staticmethod + def get_api_url(): + return reverse('api-bom-report-list') + @classmethod def getSubdir(cls): return 'bom' @@ -430,6 +444,10 @@ class PurchaseOrderReport(ReportTemplateBase): Render a report against a PurchaseOrder object """ + @staticmethod + def get_api_url(): + return reverse('api-po-report-list') + @classmethod def getSubdir(cls): return 'purchaseorder' @@ -464,6 +482,10 @@ class SalesOrderReport(ReportTemplateBase): Render a report against a SalesOrder object """ + @staticmethod + def get_api_url(): + return reverse('api-so-report-list') + @classmethod def getSubdir(cls): return 'salesorder' diff --git a/InvenTree/report/templates/report/inventree_test_report_base.html b/InvenTree/report/templates/report/inventree_test_report_base.html index 4c585d531b..d6d9c5644f 100644 --- a/InvenTree/report/templates/report/inventree_test_report_base.html +++ b/InvenTree/report/templates/report/inventree_test_report_base.html @@ -56,6 +56,10 @@ content: "{% trans 'Stock Item Test Report' %}"; {% endblock %} +{% block pre_page_content %} + +{% endblock %} + {% block page_content %}
                @@ -80,6 +84,7 @@ content: "{% trans 'Stock Item Test Report' %}";
                +{% if resul_list|length > 0 %}

                {% trans "Test Results" %}

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

                {% trans "Installed Items" %}

                + + + + + + {% for sub_item in installed_items %} + + + + + {% endfor %} + +
                + + {{ sub_item.part.full_name }} + + {% if sub_item.serialized %} + {% trans "Serial" %}: {{ sub_item.serial }} + {% else %} + {% trans "Quantity" %}: {% decimal sub_item.quantity %} + {% endif %} +
                + +{% endif %} + +{% endblock %} + +{% block post_page_content %} {% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 3fc440cae4..70ab939ff1 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -2,17 +2,21 @@ JSON API for the Stock app """ -from django_filters.rest_framework import FilterSet, DjangoFilterBackend -from django_filters import NumberFilter - -from rest_framework import status - from django.conf.urls import url, include from django.urls import reverse from django.http import JsonResponse from django.db.models import Q from django.utils.translation import ugettext_lazy as _ +from rest_framework import status +from rest_framework.serializers import ValidationError +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import generics, filters, permissions + +from django_filters.rest_framework import DjangoFilterBackend +from django_filters import rest_framework as rest_filters + from .models import StockLocation, StockItem from .models import StockItemTracking from .models import StockItemAttachment @@ -44,11 +48,6 @@ from decimal import Decimal, InvalidOperation from datetime import datetime, timedelta -from rest_framework.serializers import ValidationError -from rest_framework.views import APIView -from rest_framework.response import Response -from rest_framework import generics, filters, permissions - class StockCategoryTree(TreeSerializer): title = _('Stock') @@ -111,20 +110,6 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView): return super().update(request, *args, **kwargs) -class StockFilter(FilterSet): - """ FilterSet for advanced stock filtering. - - Allows greater-than / less-than filtering for stock quantity - """ - - min_stock = NumberFilter(name='quantity', lookup_expr='gte') - max_stock = NumberFilter(name='quantity', lookup_expr='lte') - - class Meta: - model = StockItem - fields = ['quantity', 'part', 'location'] - - class StockAdjust(APIView): """ A generic class for handling stocktake actions. @@ -135,9 +120,6 @@ class StockAdjust(APIView): - StockAdd: add stock items - StockRemove: remove stock items - StockTransfer: transfer stock items - - # TODO - This needs serious refactoring!!! - """ queryset = StockItem.objects.none() @@ -158,7 +140,10 @@ class StockAdjust(APIView): elif 'items' in request.data: _items = request.data['items'] else: - raise ValidationError({'items': 'Request must contain list of stock items'}) + _items = [] + + if len(_items) == 0: + raise ValidationError(_('Request must contain list of stock items')) # List of validated items self.items = [] @@ -166,13 +151,22 @@ class StockAdjust(APIView): for entry in _items: if not type(entry) == dict: - raise ValidationError({'error': 'Improperly formatted data'}) + raise ValidationError(_('Improperly formatted data')) + + # Look for a 'pk' value (use 'id' as a backup) + pk = entry.get('pk', entry.get('id', None)) + + try: + pk = int(pk) + except (ValueError, TypeError): + raise ValidationError(_('Each entry must contain a valid integer primary-key')) try: - 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'}) + except (StockItem.DoesNotExist): + raise ValidationError({ + pk: [_('Primary key does not match valid stock item')] + }) if self.allow_missing_quantity and 'quantity' not in entry: entry['quantity'] = item.quantity @@ -180,16 +174,21 @@ class StockAdjust(APIView): try: quantity = Decimal(str(entry.get('quantity', None))) except (ValueError, TypeError, InvalidOperation): - raise ValidationError({'quantity': "Each entry must contain a valid quantity value"}) + raise ValidationError({ + pk: [_('Invalid quantity value')] + }) if quantity < 0: - raise ValidationError({'quantity': 'Quantity field must not be less than zero'}) + raise ValidationError({ + pk: [_('Quantity must not be less than zero')] + }) self.items.append({ 'item': item, 'quantity': quantity }) + # Extract 'notes' field self.notes = str(request.data.get('notes', '')) @@ -243,6 +242,11 @@ class StockRemove(StockAdjust): for item in self.items: + if item['quantity'] > item['item'].quantity: + raise ValidationError({ + item['item'].pk: [_('Specified quantity exceeds stock quantity')] + }) + if item['item'].take_stock(item['quantity'], request.user, notes=self.notes): n += 1 @@ -258,19 +262,24 @@ class StockTransfer(StockAdjust): def post(self, request, *args, **kwargs): - self.get_items(request) - data = request.data try: location = StockLocation.objects.get(pk=data.get('location', None)) except (ValueError, StockLocation.DoesNotExist): - raise ValidationError({'location': 'Valid location must be specified'}) + raise ValidationError({'location': [_('Valid location must be specified')]}) n = 0 + self.get_items(request) + for item in self.items: + if item['quantity'] > item['item'].quantity: + raise ValidationError({ + item['item'].pk: [_('Specified quantity exceeds stock quantity')] + }) + # If quantity is not specified, move the entire stock if item['quantity'] in [0, None]: item['quantity'] = item['item'].quantity @@ -354,25 +363,135 @@ class StockLocationList(generics.ListCreateAPIView): ordering_fields = [ 'name', 'items', + 'level', + 'tree_id', + 'lft', ] + ordering = [ + 'tree_id', + 'lft', + 'name', + ] + + +class StockFilter(rest_filters.FilterSet): + """ + FilterSet for StockItem LIST API + """ + + # Part name filters + name = rest_filters.CharFilter(label='Part name (case insensitive)', field_name='part__name', lookup_expr='iexact') + name_contains = rest_filters.CharFilter(label='Part name contains (case insensitive)', field_name='part__name', lookup_expr='icontains') + name_regex = rest_filters.CharFilter(label='Part name (regex)', field_name='part__name', lookup_expr='iregex') + + # Part IPN filters + IPN = rest_filters.CharFilter(label='Part IPN (case insensitive)', field_name='part__IPN', lookup_expr='iexact') + IPN_contains = rest_filters.CharFilter(label='Part IPN contains (case insensitive)', field_name='part__IPN', lookup_expr='icontains') + IPN_regex = rest_filters.CharFilter(label='Part IPN (regex)', field_name='part__IPN', lookup_expr='iregex') + + # Part attribute filters + assembly = rest_filters.BooleanFilter(label="Assembly", field_name='part__assembly') + active = rest_filters.BooleanFilter(label="Active", field_name='part__active') + + min_stock = rest_filters.NumberFilter(label='Minimum stock', field_name='quantity', lookup_expr='gte') + max_stock = rest_filters.NumberFilter(label='Maximum stock', field_name='quantity', lookup_expr='lte') + + in_stock = rest_filters.BooleanFilter(label='In Stock', method='filter_in_stock') + + def filter_in_stock(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.filter(StockItem.IN_STOCK_FILTER) + else: + queryset = queryset.exclude(StockItem.IN_STOCK_FILTER) + + return queryset + + batch = rest_filters.CharFilter(label="Batch code filter (case insensitive)", lookup_expr='iexact') + + batch_regex = rest_filters.CharFilter(label="Batch code filter (regex)", field_name='batch', lookup_expr='iregex') + + is_building = rest_filters.BooleanFilter(label="In production") + + # Serial number filtering + serial_gte = rest_filters.NumberFilter(label='Serial number GTE', field_name='serial', lookup_expr='gte') + serial_lte = rest_filters.NumberFilter(label='Serial number LTE', field_name='serial', lookup_expr='lte') + serial = rest_filters.NumberFilter(label='Serial number', field_name='serial', lookup_expr='exact') + + serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized') + + def filter_serialized(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.exclude(serial=None) + else: + queryset = queryset.filter(serial=None) + + return queryset + + installed = rest_filters.BooleanFilter(label='Installed in other stock item', method='filter_installed') + + def filter_installed(self, queryset, name, value): + """ + Filter stock items by "belongs_to" field being empty + """ + + if str2bool(value): + queryset = queryset.exclude(belongs_to=None) + else: + queryset = queryset.filter(belongs_to=None) + + return queryset + + sent_to_customer = rest_filters.BooleanFilter(label='Sent to customer', method='filter_sent_to_customer') + + def filter_sent_to_customer(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.exclude(customer=None) + else: + queryset = queryset.filter(customer=None) + + return queryset + + depleted = rest_filters.BooleanFilter(label='Depleted', method='filter_depleted') + + def filter_depleted(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.filter(quantity__lte=0) + else: + queryset = queryset.exclude(quantity__lte=0) + + return queryset + + has_purchase_price = rest_filters.BooleanFilter(label='Has purchase price', method='filter_has_purchase_price') + + def filter_has_purchase_price(self, queryset, name, value): + + if str2bool(value): + queryset = queryset.exclude(purcahse_price=None) + else: + queryset = queryset.filter(purchase_price=None) + + return queryset + + # Update date filters + updated_before = rest_filters.DateFilter(label='Updated before', field_name='updated', lookup_expr='lte') + updated_after = rest_filters.DateFilter(label='Updated after', field_name='updated', lookup_expr='gte') + class StockList(generics.ListCreateAPIView): """ API endpoint for list view of Stock objects - GET: Return a list of all StockItem objects (with optional query filters) - POST: Create a new StockItem - - Additional query parameters are available: - - location: Filter stock by location - - category: Filter by parts belonging to a certain category - - supplier: Filter by supplier - - ancestor: Filter by an 'ancestor' StockItem - - status: Filter by the StockItem status """ serializer_class = StockItemSerializer queryset = StockItem.objects.all() + filterset_class = StockFilter def create(self, request, *args, **kwargs): """ @@ -389,7 +508,6 @@ class StockList(generics.ListCreateAPIView): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - # TODO - Save the user who created this item item = serializer.save() # A location was *not* specified - try to infer it @@ -543,24 +661,11 @@ class StockList(generics.ListCreateAPIView): if belongs_to: queryset = queryset.filter(belongs_to=belongs_to) - # Filter by batch code - batch = params.get('batch', None) - - if batch is not None: - queryset = queryset.filter(batch=batch) - build = params.get('build', None) if build: queryset = queryset.filter(build=build) - # Filter by 'is building' status - is_building = params.get('is_building', None) - - if is_building: - is_building = str2bool(is_building) - queryset = queryset.filter(is_building=is_building) - sales_order = params.get('sales_order', None) if sales_order: @@ -578,19 +683,6 @@ class StockList(generics.ListCreateAPIView): # Note: The "installed_in" field is called "belongs_to" queryset = queryset.filter(belongs_to=installed_in) - # Filter stock items which are installed in another stock item - installed = params.get('installed', None) - - if installed is not None: - installed = str2bool(installed) - - if installed: - # Exclude items which are *not* installed in another item - queryset = queryset.exclude(belongs_to=None) - else: - # Exclude items which are instaled in another item - queryset = queryset.filter(belongs_to=None) - if common.settings.stock_expiry_enabled(): # Filter by 'expired' status @@ -629,61 +721,7 @@ class StockList(generics.ListCreateAPIView): if customer: queryset = queryset.filter(customer=customer) - # Filter if items have been sent to a customer (any customer) - sent_to_customer = params.get('sent_to_customer', None) - - if sent_to_customer is not None: - sent_to_customer = str2bool(sent_to_customer) - - if sent_to_customer: - queryset = queryset.exclude(customer=None) - else: - queryset = queryset.filter(customer=None) - - # Filter by "serialized" status? - serialized = params.get('serialized', None) - - if serialized is not None: - serialized = str2bool(serialized) - - if serialized: - queryset = queryset.exclude(serial=None) - else: - queryset = queryset.filter(serial=None) - - # Filter by serial number? - serial_number = params.get('serial', None) - - if serial_number is not None: - queryset = queryset.filter(serial=serial_number) - - # Filter by range of serial numbers? - serial_number_gte = params.get('serial_gte', None) - serial_number_lte = params.get('serial_lte', None) - - if serial_number_gte is not None or serial_number_lte is not None: - queryset = queryset.exclude(serial=None) - - if serial_number_gte is not None: - queryset = queryset.filter(serial__gte=serial_number_gte) - - if serial_number_lte is not None: - queryset = queryset.filter(serial__lte=serial_number_lte) - - # Filter by "in_stock" status - in_stock = params.get('in_stock', None) - - if in_stock is not None: - in_stock = str2bool(in_stock) - - if in_stock: - # Filter out parts which are not actually "in stock" - queryset = queryset.filter(StockItem.IN_STOCK_FILTER) - else: - # Only show parts which are not in stock - queryset = queryset.exclude(StockItem.IN_STOCK_FILTER) - - # Filter by 'allocated' patrs? + # Filter by 'allocated' parts? allocated = params.get('allocated', None) if allocated is not None: @@ -696,37 +734,6 @@ class StockList(generics.ListCreateAPIView): # Filter StockItem without build allocations or sales order allocations queryset = queryset.filter(Q(sales_order_allocations__isnull=True) & Q(allocations__isnull=True)) - # Do we wish to filter by "active parts" - active = params.get('active', None) - - if active is not None: - active = str2bool(active) - queryset = queryset.filter(part__active=active) - - # Do we wish to filter by "assembly parts" - assembly = params.get('assembly', None) - - if assembly is not None: - assembly = str2bool(assembly) - queryset = queryset.filter(part__assembly=assembly) - - # Filter by 'depleted' status - depleted = params.get('depleted', None) - - if depleted is not None: - depleted = str2bool(depleted) - - if depleted: - queryset = queryset.filter(quantity__lte=0) - else: - queryset = queryset.exclude(quantity__lte=0) - - # Filter by internal part number - ipn = params.get('IPN', None) - - if ipn is not None: - queryset = queryset.filter(part__IPN=ipn) - # Does the client wish to filter by the Part ID? part_id = params.get('part', None) @@ -825,39 +832,6 @@ class StockList(generics.ListCreateAPIView): if manufacturer is not None: queryset = queryset.filter(supplier_part__manufacturer_part__manufacturer=manufacturer) - """ - Filter by the 'last updated' date of the stock item(s): - - - updated_before=? : Filter stock items which were last updated *before* the provided date - - updated_after=? : Filter stock items which were last updated *after* the provided date - """ - - date_fmt = '%Y-%m-%d' # ISO format date string - - updated_before = params.get('updated_before', None) - updated_after = params.get('updated_after', None) - - if updated_before: - try: - updated_before = datetime.strptime(str(updated_before), date_fmt).date() - queryset = queryset.filter(updated__lte=updated_before) - - print("Before:", updated_before.isoformat()) - except (ValueError, TypeError): - # Account for improperly formatted date string - print("After before:", str(updated_before)) - pass - - if updated_after: - try: - updated_after = datetime.strptime(str(updated_after), date_fmt).date() - queryset = queryset.filter(updated__gte=updated_after) - print("After:", updated_after.isoformat()) - except (ValueError, TypeError): - # Account for improperly formatted date string - print("After error:", str(updated_after)) - pass - # Optionally, limit the maximum number of returned results max_results = params.get('max_results', None) @@ -885,9 +859,6 @@ class StockList(generics.ListCreateAPIView): filters.OrderingFilter, ] - filter_fields = [ - ] - ordering_fields = [ 'part__name', 'part__IPN', @@ -931,6 +902,24 @@ class StockAttachmentList(generics.ListCreateAPIView, AttachmentMixin): ] +class StockAttachmentDetail(generics.RetrieveUpdateDestroyAPIView, AttachmentMixin): + """ + Detail endpoint for StockItemAttachment + """ + + queryset = StockItemAttachment.objects.all() + serializer_class = StockItemAttachmentSerializer + + +class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView): + """ + Detail endpoint for StockItemTestResult + """ + + queryset = StockItemTestResult.objects.all() + serializer_class = StockItemTestResultSerializer + + class StockItemTestResultList(generics.ListCreateAPIView): """ API endpoint for listing (and creating) a StockItemTestResult object. @@ -979,6 +968,15 @@ class StockItemTestResultList(generics.ListCreateAPIView): test_result.save() +class StockTrackingDetail(generics.RetrieveAPIView): + """ + Detail API endpoint for StockItemTracking model + """ + + queryset = StockItemTracking.objects.all() + serializer_class = StockTrackingSerializer + + class StockTrackingList(generics.ListAPIView): """ API endpoint for list view of StockItemTracking objects. @@ -1119,41 +1117,41 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = LocationSerializer -stock_endpoints = [ - url(r'^$', StockDetail.as_view(), name='api-stock-detail'), -] - -location_endpoints = [ - url(r'^(?P\d+)/', LocationDetail.as_view(), name='api-location-detail'), - - url(r'^.*$', StockLocationList.as_view(), name='api-location-list'), -] - stock_api_urls = [ - url(r'location/', include(location_endpoints)), + url(r'^location/', include([ + url(r'^(?P\d+)/', LocationDetail.as_view(), name='api-location-detail'), + url(r'^.*$', StockLocationList.as_view(), name='api-location-list'), + ])), - # These JSON endpoints have been replaced (for now) with server-side form rendering - 02/06/2019 - 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'), + # Endpoints for bulk stock adjustment actions + 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'), - # Base URL for StockItemAttachment API endpoints + # StockItemAttachment API endpoints url(r'^attachment/', include([ + url(r'^(?P\d+)/', StockAttachmentDetail.as_view(), name='api-stock-attachment-detail'), url(r'^$', StockAttachmentList.as_view(), name='api-stock-attachment-list'), ])), - # Base URL for StockItemTestResult API endpoints + # StockItemTestResult API endpoints url(r'^test/', include([ - url(r'^$', StockItemTestResultList.as_view(), name='api-stock-test-result-list'), + url(r'^(?P\d+)/', StockItemTestResultDetail.as_view(), name='api-stock-test-result-detail'), + url(r'^.*$', StockItemTestResultList.as_view(), name='api-stock-test-result-list'), ])), - url(r'track/?', StockTrackingList.as_view(), name='api-stock-track'), + # StockItemTracking API endpoints + url(r'^track/', include([ + url(r'^(?P\d+)/', StockTrackingDetail.as_view(), name='api-stock-tracking-detail'), + url(r'^.*$', StockTrackingList.as_view(), name='api-stock-tracking-list'), + ])), - url(r'^tree/?', StockCategoryTree.as_view(), name='api-stock-tree'), + url(r'^tree/', StockCategoryTree.as_view(), name='api-stock-tree'), # Detail for a single stock item - url(r'^(?P\d+)/', include(stock_endpoints)), + url(r'^(?P\d+)/', StockDetail.as_view(), name='api-stock-detail'), + # Anything else url(r'^.*$', StockList.as_view(), name='api-stock-list'), ] diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 92089623f9..b23b71a2d6 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -13,7 +13,6 @@ from django.core.exceptions import ValidationError from mptt.fields import TreeNodeChoiceField -from InvenTree.helpers import GetExportFormats from InvenTree.forms import HelperForm from InvenTree.fields import RoundingDecimalFormField from InvenTree.fields import DatePickerFormField @@ -23,22 +22,6 @@ from report.models import TestReport from part.models import Part from .models import StockLocation, StockItem, StockItemTracking -from .models import StockItemAttachment -from .models import StockItemTestResult - - -class EditStockItemAttachmentForm(HelperForm): - """ - Form for creating / editing a StockItemAttachment object - """ - - class Meta: - model = StockItemAttachment - fields = [ - 'stock_item', - 'attachment', - 'comment' - ] class AssignStockItemToCustomerForm(HelperForm): @@ -65,23 +48,6 @@ class ReturnStockItemForm(HelperForm): ] -class EditStockItemTestResultForm(HelperForm): - """ - Form for creating / editing a StockItemTestResult object. - """ - - class Meta: - model = StockItemTestResult - fields = [ - 'stock_item', - 'test', - 'result', - 'value', - 'attachment', - 'notes', - ] - - class EditStockLocationForm(HelperForm): """ Form for editing a StockLocation """ @@ -259,33 +225,6 @@ class TestReportFormatForm(HelperForm): template = forms.ChoiceField(label=_('Template'), help_text=_('Select test report template')) -class ExportOptionsForm(HelperForm): - """ Form for selecting stock export options """ - - file_format = forms.ChoiceField(label=_('File Format'), help_text=_('Select output file format')) - - include_sublocations = forms.BooleanField(required=False, initial=True, label=_('Include sublocations'), help_text=_("Include stock items in sub locations")) - - class Meta: - model = StockLocation - fields = [ - 'file_format', - 'include_sublocations', - ] - - def get_format_choices(self): - """ File format choices """ - - choices = [(x, x.upper()) for x in GetExportFormats()] - - return choices - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fields['file_format'].choices = self.get_format_choices() - - class InstallStockForm(HelperForm): """ Form for manually installing a stock item into another stock item @@ -361,50 +300,6 @@ class UninstallStockForm(forms.ModelForm): ] -class AdjustStockForm(forms.ModelForm): - """ Form for performing simple stock adjustments. - - - Add stock - - Remove stock - - Count stock - - Move stock - - This form is used for managing stock adjuments for single or multiple stock items. - """ - - destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Destination'), required=True, help_text=_('Destination stock location')) - - note = forms.CharField(label=_('Notes'), required=True, help_text=_('Add note (required)')) - - # transaction = forms.BooleanField(required=False, initial=False, label='Create Transaction', help_text='Create a stock transaction for these parts') - - confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm stock adjustment'), help_text=_('Confirm movement of stock items')) - - set_loc = forms.BooleanField(required=False, initial=False, label=_('Set Default Location'), help_text=_('Set the destination as the default location for selected parts')) - - class Meta: - model = StockItem - - fields = [ - 'destination', - 'note', - # 'transaction', - 'confirm', - ] - - -class EditStockItemStatusForm(HelperForm): - """ - Simple form for editing StockItem status field - """ - - class Meta: - model = StockItem - fields = [ - 'status', - ] - - class EditStockItemForm(HelperForm): """ Form for editing a StockItem object. Note that not all fields can be edited here (even if they can be specified during creation. diff --git a/InvenTree/stock/migrations/0065_auto_20210701_0509.py b/InvenTree/stock/migrations/0065_auto_20210701_0509.py new file mode 100644 index 0000000000..99cde1e7f7 --- /dev/null +++ b/InvenTree/stock/migrations/0065_auto_20210701_0509.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.4 on 2021-07-01 05:09 + +import InvenTree.fields +from django.db import migrations +import djmoney.models.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0064_auto_20210621_1724'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitem', + name='purchase_price', + field=InvenTree.fields.InvenTreeModelMoneyField(blank=True, currency_choices=[], decimal_places=4, default_currency='', help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'), + ), + migrations.AlterField( + model_name='stockitem', + name='purchase_price_currency', + field=djmoney.models.fields.CurrencyField(choices=[], default='', editable=False, max_length=3), + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 9786b360d9..ee10bd3ed7 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -20,14 +20,10 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver -from common.settings import currency_code_default - from markdownx.models import MarkdownxField from mptt.models import MPTTModel, TreeForeignKey -from djmoney.models.fields import MoneyField - from decimal import Decimal, InvalidOperation from datetime import datetime, timedelta from InvenTree import helpers @@ -38,7 +34,7 @@ import label.models from InvenTree.status_codes import StockStatus, StockHistoryCode from InvenTree.models import InvenTreeTree, InvenTreeAttachment -from InvenTree.fields import InvenTreeURLField +from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField from users.models import Owner @@ -52,6 +48,10 @@ class StockLocation(InvenTreeTree): Stock locations can be heirarchical as required """ + @staticmethod + def get_api_url(): + return reverse('api-location-list') + owner = models.ForeignKey(Owner, on_delete=models.SET_NULL, blank=True, null=True, verbose_name=_('Owner'), help_text=_('Select Owner'), @@ -161,6 +161,10 @@ class StockItem(MPTTModel): packaging: Description of how the StockItem is packaged (e.g. "reel", "loose", "tape" etc) """ + @staticmethod + def get_api_url(): + return reverse('api-stock-list') + # A Query filter which will be re-used in multiple places to determine if a StockItem is actually "in stock" IN_STOCK_FILTER = Q( quantity__gt=0, @@ -533,10 +537,9 @@ class StockItem(MPTTModel): help_text=_('Stock Item Notes') ) - purchase_price = MoneyField( + purchase_price = InvenTreeModelMoneyField( max_digits=19, decimal_places=4, - default_currency=currency_code_default(), blank=True, null=True, verbose_name=_('Purchase Price'), @@ -1208,7 +1211,7 @@ class StockItem(MPTTModel): # We need to split the stock! # Split the existing StockItem in two - self.splitStock(quantity, location, user) + self.splitStock(quantity, location, user, **{'notes': notes}) return True @@ -1608,6 +1611,10 @@ class StockItemAttachment(InvenTreeAttachment): Model for storing file attachments against a StockItem object. """ + @staticmethod + def get_api_url(): + return reverse('api-stock-attachment-list') + def getSubdir(self): return os.path.join("stock_files", str(self.stock_item.id)) @@ -1639,6 +1646,10 @@ class StockItemTracking(models.Model): deltas: The changes associated with this history item """ + @staticmethod + def get_api_url(): + return reverse('api-stock-tracking-list') + def get_absolute_url(self): return '/stock/track/{pk}'.format(pk=self.id) @@ -1697,6 +1708,10 @@ class StockItemTestResult(models.Model): date: Date the test result was recorded """ + @staticmethod + def get_api_url(): + return reverse('api-stock-test-result-list') + def save(self, *args, **kwargs): super().clean() diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index a0b7e3403a..a175787c63 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -260,12 +260,15 @@ class LocationSerializer(InvenTreeModelSerializer): items = serializers.IntegerField(source='item_count', read_only=True) + level = serializers.IntegerField(read_only=True) + class Meta: model = StockLocation fields = [ 'pk', 'url', 'name', + 'level', 'description', 'parent', 'pathstring', @@ -288,6 +291,8 @@ class StockItemAttachmentSerializer(InvenTreeModelSerializer): attachment = InvenTreeAttachmentSerializerField(required=True) + # TODO: Record the uploading user when creating or updating an attachment! + class Meta: model = StockItemAttachment diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index 5d551c29fb..8a00c1c5e6 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -3,44 +3,360 @@ {% load static %} {% load inventree_extras %} {% load i18n %} +{% load markdownify %} {% block menubar %} -{% include "stock/navbar.html" with tab="tracking" %} +{% include "stock/navbar.html" %} {% endblock %} -{% block heading %} -{% trans "Stock Tracking Information" %} -{% endblock %} +{% block page_content %} -{% block details %} +
                +
                +

                {% trans "Stock Tracking Information" %}

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

                {% trans "Child Stock Items" %}

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

                {% trans "Test Data" %}

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

                {% trans "Attachments" %}

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

                {% trans "Stock Item Notes" %}

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

                {% trans "Installed Stock Items" %}

                +
                +
                +
                +
                +
                {% endblock %} {% block js_ready %} {{ block.super }} + loadInstalledInTable( + $('#installed-table'), + { + stock_item: {{ item.pk }}, + part: {{ item.part.pk }}, + quantity: {{ item.quantity }}, + } + ); + + $('#multi-item-uninstall').click(function() { + + var selections = $('#installed-table').bootstrapTable('getSelections'); + + var items = []; + + selections.forEach(function(item) { + items.push(item.pk); + }); + + launchModalForm( + "{% url 'stock-item-uninstall' %}", + { + data: { + 'items[]': items, + }, + reload: true, + } + ); + }); + + $('#edit-notes').click(function() { + constructForm('{% url "api-stock-detail" item.pk %}', { + fields: { + notes: { + multiline: true, + } + }, + title: '{% trans "Edit Notes" %}', + reload: true, + }); + }); + + enableDragAndDrop( + '#attachment-dropzone', + "{% url 'api-stock-attachment-list' %}", + { + data: { + stock_item: {{ item.id }}, + }, + label: 'attachment', + success: function(data, status, xhr) { + reloadAttachmentTable(); + } + } + ); + + loadAttachmentTable( + '{% url "api-stock-attachment-list" %}', + { + filters: { + stock_item: {{ item.pk }}, + }, + onEdit: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + fields: { + comment: {}, + }, + title: '{% trans "Edit Attachment" %}', + onSuccess: reloadAttachmentTable + }); + }, + onDelete: function(pk) { + var url = `/api/stock/attachment/${pk}/`; + + constructForm(url, { + method: 'DELETE', + confirmMessage: '{% trans "Confirm Delete Operation" %}', + title: '{% trans "Delete Attachment" %}', + onSuccess: reloadAttachmentTable, + }); + } + } + ); + + $("#new-attachment").click(function() { + + constructForm( + '{% url "api-stock-attachment-list" %}', + { + method: 'POST', + fields: { + attachment: {}, + comment: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + }, + }, + reload: true, + title: '{% trans "Add Attachment" %}', + } + ); + }); + + loadStockTestResultsTable( + $("#test-result-table"), { + part: {{ item.part.id }}, + stock_item: {{ item.id }}, + } + ); + + function reloadTable() { + $("#test-result-table").bootstrapTable("refresh"); + } + + {% if item.has_test_reports %} + $("#test-report").click(function() { + printTestReports([{{ item.pk }}]); + }); + {% endif %} + + {% if user.is_staff %} + $("#delete-test-results").click(function() { + launchModalForm( + "{% url 'stock-item-delete-test-data' item.id %}", + { + success: reloadTable, + } + ); + }); + {% endif %} + + $("#add-test-result").click(function() { + + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-add', function() { + var button = $(this); + + var test_name = button.attr('pk'); + + constructForm('{% url "api-stock-test-result-list" %}', { + method: 'POST', + fields: { + test: { + value: test_name, + }, + result: {}, + value: {}, + attachment: {}, + notes: {}, + stock_item: { + value: {{ item.pk }}, + hidden: true, + } + }, + title: '{% trans "Add Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-edit', function() { + var button = $(this); + + var pk = button.attr('pk'); + + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + fields: { + test: {}, + result: {}, + value: {}, + attachment: {}, + notes: {}, + }, + title: '{% trans "Edit Test Result" %}', + onSuccess: reloadTable, + }); + }); + + $("#test-result-table").on('click', '.button-test-delete', function() { + var button = $(this); + + var pk = button.attr('pk'); + + var url = `/api/stock/test/${pk}/`; + + constructForm(url, { + method: 'DELETE', + title: '{% trans "Delete Test Result" %}', + onSuccess: reloadTable, + }); + }); + + {% if item.child_count > 0 %} + loadStockTable($("#childs-stock-table"), { + params: { + location_detail: true, + part_detail: false, + ancestor: {{ item.id }}, + }, + name: 'item-childs', + groupByField: 'location', + buttons: [ + '#stock-options', + ], + url: "{% url 'api-stock-list' %}", + }); + {% endif %} + $("#new-entry").click(function() { launchModalForm( "{% url 'stock-tracking-create' item.id %}", @@ -57,7 +373,7 @@ item: {{ item.pk }}, user_detail: true, }, - url: "{% url 'api-stock-track' %}", + url: "{% url 'api-stock-tracking-list' %}", }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_attachments.html b/InvenTree/stock/templates/stock/item_attachments.html deleted file mode 100644 index a022403d02..0000000000 --- a/InvenTree/stock/templates/stock/item_attachments.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='attachments' %} -{% endblock %} - -{% block heading %} -{% trans "Stock Item Attachments" %} -{% endblock %} - -{% block details %} -{% include "attachment_table.html" with attachments=item.attachments.all %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -enableDragAndDrop( - '#attachment-dropzone', - "{% url 'stock-item-attachment-create' %}", - { - data: { - stock_item: {{ item.id }}, - }, - label: 'attachment', - success: function(data, status, xhr) { - location.reload(); - } - } - ); - -$("#new-attachment").click(function() { - launchModalForm("{% url 'stock-item-attachment-create' %}?item={{ item.id }}", - { - reload: true, - }); -}); - -$("#attachment-table").on('click', '.attachment-edit-button', function() { - var button = $(this); - - var url = `/stock/item/attachment/${button.attr('pk')}/edit/`; - - launchModalForm(url, - { - reload: true, - }); -}); - -$("#attachment-table").on('click', '.attachment-delete-button', function() { - var button = $(this); - - var url = `/stock/item/attachment/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - success: function() { - location.reload(); - } - }); -}); - -$("#attachment-table").inventreeTable({ -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index bf9d10590f..547806e256 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -235,7 +235,7 @@ {% trans "Base Part" %} {% if roles.part.view %} - + {% endif %} {{ item.part.full_name }} {% if roles.part.view %} @@ -247,7 +247,19 @@ {% trans "Serial Number" %} - {{ item.serial }} + + {% if previous %} + + {{ previous.serial }} ‹ + + {% endif %} + {{ item.serial }} + {% if next %} + + › {{ next.serial }} + + {% endif %} + {% else %} @@ -416,6 +428,7 @@ {% endif %} + {% endblock %} {% block js_ready %} @@ -490,13 +503,14 @@ $("#stock-edit").click(function () { }); $('#stock-edit-status').click(function () { - launchModalForm( - "{% url 'stock-item-edit-status' item.id %}", - { - reload: true, - submit_text: '{% trans "Save" %}', - } - ); + + constructForm('{% url "api-stock-detail" item.pk %}', { + fields: { + status: {}, + }, + reload: true, + title: '{% trans "Edit Stock Status" %}', + }); }); {% endif %} @@ -521,14 +535,21 @@ $("#barcode-scan-into-location").click(function() { }); function itemAdjust(action) { - launchModalForm("/stock/adjust/", + + inventreeGet( + '{% url "api-stock-detail" item.pk %}', { - data: { - action: action, - item: {{ item.id }}, - }, - reload: true, - follow: true, + part_detail: true, + location_detail: true, + }, + { + success: function(item) { + adjustStock(action, [item], { + onSuccess: function() { + location.reload(); + } + }); + } } ); } @@ -541,7 +562,7 @@ $("#stock-delete").click(function () { launchModalForm( "{% url 'stock-item-delete' item.id %}", { - redirect: "{% url 'part-stock' item.part.id %}" + redirect: "{% url 'part-detail' item.part.id %}" } ); }); @@ -590,4 +611,9 @@ $("#stock-return-from-customer").click(function() { {% endif %} +attachNavCallbacks({ + name: 'stockitem', + default: 'history' +}); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/item_childs.html b/InvenTree/stock/templates/stock/item_childs.html deleted file mode 100644 index f5d80e5ad1..0000000000 --- a/InvenTree/stock/templates/stock/item_childs.html +++ /dev/null @@ -1,45 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - - -{% block menubar %} -{% include "stock/navbar.html" with tab='children' %} -{% endblock %} - -{% block heading %} -{% trans "Child Stock Items" %} -{% endblock %} - -{% block details %} -{% if item.child_count > 0 %} -{% include "stock_table.html" %} -{% else %} -
                - {% trans "This stock item does not have any child items" %} -
                -{% endif %} - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -{% if item.child_count > 0 %} -loadStockTable($("#stock-table"), { - params: { - location_detail: true, - part_detail: false, - ancestor: {{ item.id }}, - }, - name: 'item-childs', - groupByField: 'location', - buttons: [ - '#stock-options', - ], - url: "{% url 'api-stock-list' %}", -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html deleted file mode 100644 index 8902fe00ef..0000000000 --- a/InvenTree/stock/templates/stock/item_installed.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='installed' %} -{% endblock %} - -{% block heading %} -{% trans "Installed Stock Items" %} -{% endblock %} - -{% block details %} -
                - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -loadInstalledInTable( - $('#installed-table'), - { - stock_item: {{ item.pk }}, - part: {{ item.part.pk }}, - quantity: {{ item.quantity }}, - } -); - -$('#multi-item-uninstall').click(function() { - - var selections = $('#installed-table').bootstrapTable('getSelections'); - - var items = []; - - selections.forEach(function(item) { - items.push(item.pk); - }); - - launchModalForm( - "{% url 'stock-item-uninstall' %}", - { - data: { - 'items[]': items, - }, - reload: true, - } - ); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_notes.html b/InvenTree/stock/templates/stock/item_notes.html deleted file mode 100644 index 788f7fb3bd..0000000000 --- a/InvenTree/stock/templates/stock/item_notes.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load inventree_extras %} -{% load i18n %} -{% load markdownify %} - -{% block menubar %} -{% include "stock/navbar.html" with tab="notes" %} -{% endblock %} - -{% block heading %} -{% trans "Stock Item Notes" %} -{% if roles.stock.change and not editing %} - -{% endif %} -{% endblock %} - -{% block details %} -{% if editing %} -
                - {% csrf_token %} - - {{ form }} -
                - -
                - -{{ form.media }} - -{% else %} -{% if item.notes %} -{{ item.notes | markdownify }} -{% endif %} - -{% endif %} - -{% endblock %} - -{% block js_ready %} - -{{ block.super }} - -{% if editing %} -{% else %} -$("#edit-notes").click(function() { - location.href = "{% url 'stock-item-notes' item.id %}?edit=1"; -}); -{% endif %} - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/item_tests.html b/InvenTree/stock/templates/stock/item_tests.html deleted file mode 100644 index 4b3d9dd028..0000000000 --- a/InvenTree/stock/templates/stock/item_tests.html +++ /dev/null @@ -1,121 +0,0 @@ -{% extends "stock/item_base.html" %} - -{% load static %} -{% load i18n %} - -{% block menubar %} -{% include "stock/navbar.html" with tab='tests' %} -{% endblock %} - -{% block heading %} -{% trans "Test Data" %} -{% endblock %} - -{% block details %} -
                -
                -
                - {% if user.is_staff %} - - {% endif %} - - -
                -
                - -
                -
                -
                - -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockTestResultsTable( - $("#test-result-table"), { - part: {{ item.part.id }}, - stock_item: {{ item.id }}, - } -); - -function reloadTable() { - location.reload(); - //$("#test-result-table").bootstrapTable("refresh"); -} - -{% if item.has_test_reports %} -$("#test-report").click(function() { - printTestReports([{{ item.pk }}]); -}); -{% endif %} - -{% if user.is_staff %} -$("#delete-test-results").click(function() { - launchModalForm( - "{% url 'stock-item-delete-test-data' item.id %}", - { - success: reloadTable, - } - ); -}); -{% endif %} - -$("#add-test-result").click(function() { - launchModalForm( - "{% url 'stock-item-test-create' %}", { - data: { - stock_item: {{ item.id }}, - }, - success: reloadTable, - focus: 'test', - } - ); -}); - -$("#test-result-table").on('click', '.button-test-add', function() { - var button = $(this); - - var test_name = button.attr('pk'); - - launchModalForm( - "{% url 'stock-item-test-create' %}", { - data: { - stock_item: {{ item.id }}, - test: test_name - }, - success: reloadTable, - focus: 'value', - } - ); -}); - -$("#test-result-table").on('click', '.button-test-edit', function() { - var button = $(this); - - var url = `/stock/item/test/${button.attr('pk')}/edit/`; - - launchModalForm(url, { - success: reloadTable, - }); -}); - -$("#test-result-table").on('click', '.button-test-delete', function() { - var button = $(this); - - var url = `/stock/item/test/${button.attr('pk')}/delete/`; - - launchModalForm(url, { - success: reloadTable, - }); -}); - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 499aaa6948..9a5aeb6a7e 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -4,7 +4,7 @@ {% load i18n %} {% block menubar %} -{% include "stock/location_navbar.html" with tab="stock" %} +{% include "stock/location_navbar.html" %} {% endblock %} {% block content %} @@ -59,11 +59,23 @@ {% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %} {% if roles.stock.change %} {% endif %} {% if roles.stock_location.change %} @@ -131,13 +143,39 @@ {% block location_content %} -
                +

                {% trans "Stock Items" %}

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

                {% trans "Sublocations" %}

                +
                +
                +
                +
                + + +
                + +
                +
                +
                + +
                +
                +
                + {% endblock %}
                @@ -152,6 +190,36 @@ toggleId: '#location-menu-toggle' }); + loadStockLocationTable($('#sublocation-table'), { + params: { + {% if location %} + parent: {{ location.pk }}, + {% else %} + parent: 'null', + {% endif %} + } + }); + + linkButtonsToSelection( + $('#sublocation-table'), + [ + '#location-print-options', + ] + ); + + $('#multi-location-print-label').click(function() { + + var selections = $('#sublocation-table').bootstrapTable('getSelections'); + + var locations = []; + + selections.forEach(function(loc) { + locations.push(loc.pk); + }); + + printStockLocationLabels(locations); + }); + {% if location %} $("#barcode-check-in").click(function() { barcodeCheckIn({{ location.id }}); @@ -159,20 +227,11 @@ {% endif %} $("#stock-export").click(function() { - launchModalForm("{% url 'stock-export-options' %}", { - submit_text: '{% trans "Export" %}', - success: function(response) { - var url = "{% url 'stock-export' %}"; - url += "?format=" + response.format; - url += "&cascade=" + response.cascade; - - {% if location %} - url += "&location={{ location.id }}"; - {% endif %} - - location.href = url; - } + exportStock({ + {% if location %} + location: {{ location.pk }} + {% endif %} }); }); @@ -215,14 +274,34 @@ }); {% if location %} - $("#location-count").click(function() { - launchModalForm("/stock/adjust/", { - data: { - action: "count", + + function adjustLocationStock(action) { + inventreeGet( + '{% url "api-stock-list" %}', + { location: {{ location.id }}, - reload: true, + in_stock: true, + part_detail: true, + location_detail: true, + }, + { + success: function(items) { + adjustStock(action, items, { + onSuccess: function() { + location.reload(); + } + }); + } } - }); + ); + } + + $("#location-count").click(function() { + adjustLocationStock('count'); + }); + + $("#location-move").click(function() { + adjustLocationStock('move'); }); $('#print-label').click(function() { @@ -265,7 +344,14 @@ {% endif %} part_detail: true, location_detail: true, + supplier_part_detail: true, }, url: "{% url 'api-stock-list' %}", }); + + attachNavCallbacks({ + name: 'stocklocation', + default: 'stock' + }); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/location_navbar.html b/InvenTree/stock/templates/stock/location_navbar.html index a4974d0d37..d03761e460 100644 --- a/InvenTree/stock/templates/stock/location_navbar.html +++ b/InvenTree/stock/templates/stock/location_navbar.html @@ -8,23 +8,15 @@ -
              • - {% if location %} - - {% else %} - - {% endif %} +
              • + {% trans "Sublocations" %}
              • - {% if location %} - - {% else %} - - {% endif %} + {% trans "Stock Items" %} diff --git a/InvenTree/stock/templates/stock/navbar.html b/InvenTree/stock/templates/stock/navbar.html index 7c7d197a1a..90c0075ba0 100644 --- a/InvenTree/stock/templates/stock/navbar.html +++ b/InvenTree/stock/templates/stock/navbar.html @@ -8,24 +8,24 @@
              • -
              • - +
              • + {% trans "History" %}
              • {% if item.part.trackable %} -
              • - +
              • + {% trans "Test Data" %}
              • {% if item.part.assembly %} -
              • - +
              • + {% trans "Installed Items" %} @@ -35,8 +35,8 @@ {% endif %} {% if item.child_count > 0 %} -
              • - +
              • + {% trans "Children" %} @@ -44,15 +44,15 @@ {% endif %} -
              • - +
              • + {% trans "Attachments" %}
              • -
              • - +
              • + {% trans "Notes" %} diff --git a/InvenTree/stock/templates/stock/sublocation.html b/InvenTree/stock/templates/stock/sublocation.html deleted file mode 100644 index be9390df3b..0000000000 --- a/InvenTree/stock/templates/stock/sublocation.html +++ /dev/null @@ -1,74 +0,0 @@ -{% extends "stock/location.html" %} - -{% load static %} -{% load i18n %} -{% load inventree_extras %} - -{% block menubar %} -{% include "stock/location_navbar.html" with tab="sublocations" %} -{% endblock %} - - -{% block location_content %} - -
                -
                -

                {% trans "Sublocations" %}

                -
                - -
                -
                - - -
                - -
                -
                -
                - -
                -
                - -{% endblock %} - -{% block js_ready %} -{{ block.super }} - -loadStockLocationTable($('#sublocation-table'), { - params: { - {% if location %} - parent: {{ location.pk }}, - {% else %} - parent: 'null', - {% endif %} - } -}); - -linkButtonsToSelection( - $('#sublocation-table'), - [ - '#location-print-options', - ] -); - -$('#multi-location-print-label').click(function() { - - var selections = $('#sublocation-table').bootstrapTable('getSelections'); - - var locations = []; - - selections.forEach(function(loc) { - locations.push(loc.pk); - }); - - printStockLocationLabels(locations); -}) - -{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index e1fb616335..74f9505c4a 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -7,8 +7,8 @@ from __future__ import unicode_literals from datetime import datetime, timedelta -from rest_framework import status from django.urls import reverse +from rest_framework import status from InvenTree.status_codes import StockStatus from InvenTree.api_tester import InvenTreeAPITestCase @@ -354,16 +354,18 @@ class StockItemTest(StockAPITestCase): self.assertContains(response, 'does not exist', status_code=status.HTTP_400_BAD_REQUEST) # POST without quantity - response = self.client.post( + response = self.post( self.list_url, - data={ + { 'part': 1, 'location': 1, - } + }, + expected_code=201, ) - self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST) - + # Item should have been created with default quantity + self.assertEqual(response.data['quantity'], 1) + # POST with quantity and part and location response = self.client.post( self.list_url, @@ -454,30 +456,32 @@ class StocktakeTest(StockAPITestCase): # POST without a PK response = self.post(url, data) - self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'must contain a valid integer primary-key', status_code=status.HTTP_400_BAD_REQUEST) - # POST with a PK but no quantity + # POST with an invalid PK data['items'] = [{ 'pk': 10 }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid pk', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'does not match valid stock item', status_code=status.HTTP_400_BAD_REQUEST) + # POST with missing quantity value data['items'] = [{ 'pk': 1234 }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) + # POST with an invalid quantity value data['items'] = [{ 'pk': 1234, 'quantity': '10x0d' }] response = self.post(url, data) - self.assertContains(response, 'must contain a valid quantity', status_code=status.HTTP_400_BAD_REQUEST) + self.assertContains(response, 'Invalid quantity value', status_code=status.HTTP_400_BAD_REQUEST) data['items'] = [{ 'pk': 1234, diff --git a/InvenTree/stock/test_views.py b/InvenTree/stock/test_views.py index c565532739..9494598430 100644 --- a/InvenTree/stock/test_views.py +++ b/InvenTree/stock/test_views.py @@ -105,31 +105,6 @@ class StockItemTest(StockViewTestCase): response = self.client.get(reverse('stock-item-qr', args=(9999,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) - def test_adjust_items(self): - url = reverse('stock-adjust') - - # Move items - response = self.client.get(url, {'stock[]': [1, 2, 3, 4, 5], 'action': 'move'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Count part - response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Remove items - response = self.client.get(url, {'location': 1, 'action': 'take'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Add items - response = self.client.get(url, {'item': 1, 'action': 'add'}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # Blank response - response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') - self.assertEqual(response.status_code, 200) - - # TODO - Tests for POST data - def test_edit_item(self): # Test edit view for StockItem response = self.client.get(reverse('stock-item-edit', args=(1,)), HTTP_X_REQUESTED_WITH='XMLHttpRequest') diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 6bc15b3505..205fb417a8 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -100,7 +100,7 @@ class StockTest(TestCase): # And there should be *no* items being build self.assertEqual(part.quantity_being_built, 0) - build = Build.objects.create(part=part, title='A test build', quantity=1) + build = Build.objects.create(reference='12345', part=part, title='A test build', quantity=1) # Add some stock items which are "building" for i in range(10): diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index dbdbdda317..434acde84e 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -14,9 +14,7 @@ location_urls = [ url(r'^edit/?', views.StockLocationEdit.as_view(), name='stock-location-edit'), url(r'^delete/?', views.StockLocationDelete.as_view(), name='stock-location-delete'), url(r'^qr_code/?', views.StockLocationQRCode.as_view(), name='stock-location-qr'), - - url(r'sublocation/', views.StockLocationDetail.as_view(template_name='stock/sublocation.html'), name='stock-location-sublocation'), - + # Anything else url('^.*$', views.StockLocationDetail.as_view(), name='stock-location-detail'), ])), @@ -24,7 +22,6 @@ location_urls = [ ] stock_item_detail_urls = [ - url(r'^edit_status/', views.StockItemEditStatus.as_view(), name='stock-item-edit-status'), url(r'^edit/', views.StockItemEdit.as_view(), name='stock-item-edit'), url(r'^convert/', views.StockItemConvert.as_view(), name='stock-item-convert'), url(r'^serialize/', views.StockItemSerialize.as_view(), name='stock-item-serialize'), @@ -37,12 +34,6 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), - url(r'^test/', views.StockItemDetail.as_view(template_name='stock/item_tests.html'), name='stock-item-test-results'), - url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'), - url(r'^attachments/', views.StockItemDetail.as_view(template_name='stock/item_attachments.html'), name='stock-item-attachments'), - url(r'^installed/', views.StockItemDetail.as_view(template_name='stock/item_installed.html'), name='stock-item-installed'), - url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), - url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), ] @@ -63,25 +54,8 @@ stock_urls = [ url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'), - # URLs for StockItem attachments - url(r'^item/attachment/', include([ - url(r'^new/', views.StockItemAttachmentCreate.as_view(), name='stock-item-attachment-create'), - url(r'^(?P\d+)/edit/', views.StockItemAttachmentEdit.as_view(), name='stock-item-attachment-edit'), - url(r'^(?P\d+)/delete/', views.StockItemAttachmentDelete.as_view(), name='stock-item-attachment-delete'), - ])), - - # URLs for StockItem tests - url(r'^item/test/', include([ - url(r'^new/', views.StockItemTestResultCreate.as_view(), name='stock-item-test-create'), - url(r'^(?P\d+)/edit/', views.StockItemTestResultEdit.as_view(), name='stock-item-test-edit'), - url(r'^(?P\d+)/delete/', views.StockItemTestResultDelete.as_view(), name='stock-item-test-delete'), - ])), - url(r'^track/', include(stock_tracking_urls)), - url(r'^adjust/?', views.StockAdjust.as_view(), name='stock-adjust'), - - url(r'^export-options/?', views.StockExportOptions.as_view(), name='stock-export-options'), url(r'^export/?', views.StockExport.as_view(), name='stock-export'), # Individual stock items diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 9a47576442..008b209bc8 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -32,7 +32,7 @@ from datetime import datetime, timedelta from company.models import Company, SupplierPart from part.models import Part -from .models import StockItem, StockLocation, StockItemTracking, StockItemAttachment, StockItemTestResult +from .models import StockItem, StockLocation, StockItemTracking import common.settings from common.models import InvenTreeSetting @@ -86,6 +86,29 @@ class StockItemDetail(InvenTreeRoleMixin, DetailView): queryset = StockItem.objects.all() model = StockItem + def get_context_data(self, **kwargs): + """ add previous and next item """ + data = super().get_context_data(**kwargs) + + if self.object.serialized: + serial_elem = {int(a.serial): a for a in self.object.part.stock_items.all() if a.serialized} + serials = serial_elem.keys() + current = int(self.object.serial) + + # previous + for nbr in range(current - 1, -1, -1): + if nbr in serials: + data['previous'] = serial_elem.get(nbr, None) + break + + # next + for nbr in range(current + 1, max(serials) + 1): + if nbr in serials: + data['next'] = serial_elem.get(nbr, None) + break + + return data + class StockItemNotes(InvenTreeRoleMixin, UpdateView): """ View for editing the 'notes' field of a StockItem object """ @@ -255,85 +278,6 @@ class StockLocationQRCode(QRCodeView): return None -class StockItemAttachmentCreate(AjaxCreateView): - """ - View for adding a new attachment for a StockItem - """ - - model = StockItemAttachment - form_class = StockForms.EditStockItemAttachmentForm - ajax_form_title = _("Add Stock Item Attachment") - ajax_template_name = "modal_form.html" - - def save(self, form, **kwargs): - """ Record the user that uploaded the attachment """ - - attachment = form.save(commit=False) - attachment.user = self.request.user - attachment.save() - - def get_data(self): - return { - 'success': _("Added attachment") - } - - def get_initial(self): - """ - Get initial data for the new StockItem attachment object. - - - Client must provide a valid StockItem ID - """ - - initials = super().get_initial() - - try: - initials['stock_item'] = StockItem.objects.get(id=self.request.GET.get('item', None)) - except (ValueError, StockItem.DoesNotExist): - pass - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemAttachmentEdit(AjaxUpdateView): - """ - View for editing a StockItemAttachment object. - """ - - model = StockItemAttachment - form_class = StockForms.EditStockItemAttachmentForm - ajax_form_title = _("Edit Stock Item Attachment") - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemAttachmentDelete(AjaxDeleteView): - """ - View for deleting a StockItemAttachment object. - """ - - model = StockItemAttachment - ajax_form_title = _("Delete Stock Item Attachment") - ajax_template_name = "attachment_delete.html" - context_object_name = "attachment" - - def get_data(self): - return { - 'danger': _("Deleted attachment"), - } - - class StockItemAssignToCustomer(AjaxUpdateView): """ View for manually assigning a StockItem to a Customer @@ -434,106 +378,6 @@ class StockItemDeleteTestData(AjaxUpdateView): return self.renderJsonResponse(request, form, data) -class StockItemTestResultCreate(AjaxCreateView): - """ - View for adding a new StockItemTestResult - """ - - model = StockItemTestResult - form_class = StockForms.EditStockItemTestResultForm - ajax_form_title = _("Add Test Result") - - def save(self, form, **kwargs): - """ - Record the user that uploaded the test result - """ - - result = form.save(commit=False) - result.user = self.request.user - result.save() - - def get_initial(self): - - initials = super().get_initial() - - try: - stock_id = self.request.GET.get('stock_item', None) - initials['stock_item'] = StockItem.objects.get(pk=stock_id) - except (ValueError, StockItem.DoesNotExist): - pass - - initials['test'] = self.request.GET.get('test', '') - - return initials - - def get_form(self): - - form = super().get_form() - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemTestResultEdit(AjaxUpdateView): - """ - View for editing a StockItemTestResult - """ - - model = StockItemTestResult - form_class = StockForms.EditStockItemTestResultForm - ajax_form_title = _("Edit Test Result") - - def get_form(self): - - form = super().get_form() - - form.fields['stock_item'].widget = HiddenInput() - - return form - - -class StockItemTestResultDelete(AjaxDeleteView): - """ - View for deleting a StockItemTestResult - """ - - model = StockItemTestResult - ajax_form_title = _("Delete Test Result") - context_object_name = "result" - - -class StockExportOptions(AjaxView): - """ Form for selecting StockExport options """ - - model = StockLocation - ajax_form_title = _('Stock Export Options') - form_class = StockForms.ExportOptionsForm - - def post(self, request, *args, **kwargs): - - self.request = request - - fmt = request.POST.get('file_format', 'csv').lower() - cascade = str2bool(request.POST.get('include_sublocations', False)) - - # Format a URL to redirect to - url = reverse('stock-export') - - url += '?format=' + fmt - url += '&cascade=' + str(cascade) - - data = { - 'form_valid': True, - 'format': fmt, - 'cascade': cascade - } - - return self.renderJsonResponse(self.request, self.form_class(), data=data) - - def get(self, request, *args, **kwargs): - return self.renderJsonResponse(request, self.form_class()) - - class StockExport(AjaxView): """ Export stock data from a particular location. Returns a file containing stock information for that location. @@ -595,11 +439,10 @@ class StockExport(AjaxView): ) if location: - # CHeck if locations should be cascading + # Check if locations should be cascading cascade = str2bool(request.GET.get('cascade', True)) stock_items = location.get_stock_items(cascade) else: - cascade = True stock_items = StockItem.objects.all() if part: @@ -873,366 +716,6 @@ class StockItemUninstall(AjaxView, FormMixin): return context -class StockAdjust(AjaxView, FormMixin): - """ View for enacting simple stock adjustments: - - - Take items from stock - - Add items to stock - - Count items - - Move stock - - Delete stock items - - """ - - ajax_template_name = 'stock/stock_adjust.html' - ajax_form_title = _('Adjust Stock') - form_class = StockForms.AdjustStockForm - stock_items = [] - role_required = 'stock.change' - - def get_GET_items(self): - """ Return list of stock items initally requested using GET. - - Items can be retrieved by: - - a) List of stock ID - stock[]=1,2,3,4,5 - b) Parent part - part=3 - c) Parent location - location=78 - d) Single item - item=2 - """ - - # Start with all 'in stock' items - items = StockItem.objects.filter(StockItem.IN_STOCK_FILTER) - - # Client provides a list of individual stock items - if 'stock[]' in self.request.GET: - items = items.filter(id__in=self.request.GET.getlist('stock[]')) - - # Client provides a PART reference - elif 'part' in self.request.GET: - items = items.filter(part=self.request.GET.get('part')) - - # Client provides a LOCATION reference - elif 'location' in self.request.GET: - items = items.filter(location=self.request.GET.get('location')) - - # Client provides a single StockItem lookup - elif 'item' in self.request.GET: - items = [StockItem.objects.get(id=self.request.GET.get('item'))] - - # Unsupported query (no items) - else: - items = [] - - for item in items: - - # Initialize quantity to zero for addition/removal - if self.stock_action in ['take', 'add']: - item.new_quantity = 0 - # Initialize quantity at full amount for counting or moving - else: - item.new_quantity = item.quantity - - return items - - def get_POST_items(self): - """ Return list of stock items sent back by client on a POST request """ - - items = [] - - for item in self.request.POST: - if item.startswith('stock-id-'): - - pk = item.replace('stock-id-', '') - q = self.request.POST[item] - - try: - stock_item = StockItem.objects.get(pk=pk) - except StockItem.DoesNotExist: - continue - - stock_item.new_quantity = q - - items.append(stock_item) - - return items - - def get_context_data(self): - - context = super().get_context_data() - - context['stock_items'] = self.stock_items - - context['stock_action'] = self.stock_action.strip().lower() - - context['stock_action_title'] = self.stock_action_title - - # Quantity column will be read-only in some circumstances - context['edit_quantity'] = not self.stock_action == 'delete' - - return context - - def get_form(self): - - form = super().get_form() - - if not self.stock_action == 'move': - form.fields.pop('destination') - form.fields.pop('set_loc') - - return form - - def get(self, request, *args, **kwargs): - - self.request = request - - # Action - self.stock_action = request.GET.get('action', '').lower() - - # Pick a default action... - if self.stock_action not in ['move', 'count', 'take', 'add', 'delete']: - self.stock_action = 'count' - - # Choose form title and action column based on the action - titles = { - 'move': [_('Move Stock Items'), _('Move')], - 'count': [_('Count Stock Items'), _('Count')], - 'take': [_('Remove From Stock'), _('Take')], - 'add': [_('Add Stock Items'), _('Add')], - 'delete': [_('Delete Stock Items'), _('Delete')], - } - - self.ajax_form_title = titles[self.stock_action][0] - self.stock_action_title = titles[self.stock_action][1] - - # Save list of items! - self.stock_items = self.get_GET_items() - - return self.renderJsonResponse(request, self.get_form()) - - def post(self, request, *args, **kwargs): - - self.request = request - - self.stock_action = request.POST.get('stock_action', 'invalid').strip().lower() - - # Update list of stock items - self.stock_items = self.get_POST_items() - - form = self.get_form() - - valid = form.is_valid() - - for item in self.stock_items: - - try: - item.new_quantity = Decimal(item.new_quantity) - except ValueError: - item.error = _('Must enter integer value') - valid = False - continue - - if item.new_quantity < 0: - item.error = _('Quantity must be positive') - valid = False - continue - - if self.stock_action in ['move', 'take']: - - if item.new_quantity > item.quantity: - item.error = _('Quantity must not exceed {x}').format(x=item.quantity) - valid = False - continue - - confirmed = str2bool(request.POST.get('confirm')) - - if not confirmed: - valid = False - form.add_error('confirm', _('Confirm stock adjustment')) - - data = { - 'form_valid': valid, - } - - if valid: - result = self.do_action() - - data['success'] = result - - # Special case - Single Stock Item - # If we deplete the stock item, we MUST redirect to a new view - single_item = len(self.stock_items) == 1 - - if result and single_item: - - # Was the entire stock taken? - item = self.stock_items[0] - - if item.quantity == 0: - # Instruct the form to redirect - data['url'] = reverse('stock-index') - - return self.renderJsonResponse(request, form, data=data) - - def do_action(self): - """ Perform stock adjustment action """ - - if self.stock_action == 'move': - destination = None - - set_default_loc = str2bool(self.request.POST.get('set_loc', False)) - - try: - destination = StockLocation.objects.get(id=self.request.POST.get('destination')) - except StockLocation.DoesNotExist: - pass - except ValueError: - pass - - return self.do_move(destination, set_default_loc) - - elif self.stock_action == 'add': - return self.do_add() - - elif self.stock_action == 'take': - return self.do_take() - - elif self.stock_action == 'count': - return self.do_count() - - elif self.stock_action == 'delete': - return self.do_delete() - - else: - return _('No action performed') - - def do_add(self): - - count = 0 - note = self.request.POST['note'] - - for item in self.stock_items: - if item.new_quantity <= 0: - continue - - item.add_stock(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _('Added stock to {n} items').format(n=count) - - def do_take(self): - - count = 0 - note = self.request.POST['note'] - - for item in self.stock_items: - if item.new_quantity <= 0: - continue - - item.take_stock(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _('Removed stock from {n} items').format(n=count) - - def do_count(self): - - count = 0 - note = self.request.POST['note'] - - for item in self.stock_items: - - item.stocktake(item.new_quantity, self.request.user, notes=note) - - count += 1 - - return _("Counted stock for {n} items".format(n=count)) - - def do_move(self, destination, set_loc=None): - """ Perform actual stock movement """ - - count = 0 - - note = self.request.POST['note'] - - for item in self.stock_items: - # Avoid moving zero quantity - if item.new_quantity <= 0: - continue - - # If we wish to set the destination location to the default one - if set_loc: - item.part.default_location = destination - item.part.save() - - # Do not move to the same location (unless the quantity is different) - if destination == item.location and item.new_quantity == item.quantity: - continue - - item.move(destination, note, self.request.user, quantity=item.new_quantity) - - count += 1 - - # Is ownership control enabled? - stock_ownership_control = InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') - - if stock_ownership_control: - # Fetch destination owner - destination_owner = destination.owner - - if destination_owner: - # Update owner - item.owner = destination_owner - item.save() - - if count == 0: - return _('No items were moved') - - else: - return _('Moved {n} items to {dest}').format( - n=count, - dest=destination.pathstring) - - def do_delete(self): - """ Delete multiple stock items """ - - count = 0 - # note = self.request.POST['note'] - - for item in self.stock_items: - - # TODO - In the future, StockItems should not be 'deleted' - # TODO - Instead, they should be marked as "inactive" - - item.delete() - - count += 1 - - return _("Deleted {n} stock items").format(n=count) - - -class StockItemEditStatus(AjaxUpdateView): - """ - View for editing stock item status field - """ - - model = StockItem - form_class = StockForms.EditStockItemStatusForm - ajax_form_title = _('Edit Stock Item Status') - - def save(self, object, form, **kwargs): - """ - Override the save method, to track the user who updated the model - """ - - item = form.save(commit=False) - - item.save(user=self.request.user) - - return item - - class StockItemEdit(AjaxUpdateView): """ View for editing details of a single StockItem diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index 434d652728..a3d793dd26 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -128,6 +128,7 @@ loadSimplePartTable("#table-bom-validation", "{% url 'api-part-list' %}", { addHeaderTitle('{% trans "Stock" %}'); addHeaderAction('recently-updated-stock', '{% trans "Recently Updated" %}', 'fa-clock'); addHeaderAction('low-stock', '{% trans "Low Stock" %}', 'fa-shopping-cart'); +addHeaderAction('depleted-stock', '{% trans "Depleted Stock" %}', 'fa-times'); addHeaderAction('stock-to-build', '{% trans "Required for Build Orders" %}', 'fa-bullhorn'); loadStockTable($('#table-recently-updated-stock'), { @@ -170,6 +171,13 @@ loadSimplePartTable("#table-low-stock", "{% url 'api-part-list' %}", { name: "low_stock_parts", }); +loadSimplePartTable("#table-depleted-stock", "{% url 'api-part-list' %}", { + params: { + depleted_stock: true, + }, + name: "depleted_stock_parts", +}); + loadSimplePartTable("#table-stock-to-build", "{% url 'api-part-list' %}", { params: { stock_to_build: true, diff --git a/InvenTree/templates/InvenTree/settings/currencies.html b/InvenTree/templates/InvenTree/settings/currencies.html index 78598236f9..6e61533e6b 100644 --- a/InvenTree/templates/InvenTree/settings/currencies.html +++ b/InvenTree/templates/InvenTree/settings/currencies.html @@ -12,6 +12,13 @@ {% block settings %} + + {% include "InvenTree/settings/header.html" %} + + {% include "InvenTree/settings/setting.html" with key="INVENTREE_DEFAULT_CURRENCY" icon="fa-globe" %} + +
                + diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 1bf5f8794a..4f49a63cb4 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -21,8 +21,10 @@ {% include "InvenTree/settings/setting.html" with key="PART_ALLOW_EDIT_IPN" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_QUANTITY_IN_FORMS" icon="fa-hashtag" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_PRICE_IN_FORMS" icon="fa-dollar-sign" %} + {% include "InvenTree/settings/setting.html" with key="PART_SHOW_RELATED" icon="fa-random" %} {% include "InvenTree/settings/setting.html" with key="PART_RECENT_COUNT" icon="fa-clock" %} - + {% include "InvenTree/settings/setting.html" with key="PART_CREATE_INITIAL" icon="fa-boxes" %} + {% include "InvenTree/settings/setting.html" with key="PART_TEMPLATE" icon="fa-clone" %} {% include "InvenTree/settings/setting.html" with key="PART_ASSEMBLY" icon="fa-tools" %} {% include "InvenTree/settings/setting.html" with key="PART_COMPONENT" icon="fa-th"%} @@ -41,6 +43,22 @@
                +

                {% trans "Part Import" %}

                + + + + + + {% include "InvenTree/settings/header.html" %} + + {% include "InvenTree/settings/setting.html" with key="PART_SHOW_IMPORT" icon="fa-file-upload" %} + +
                + + +

                {% trans "Part Parameter Templates" %}

                @@ -58,7 +76,7 @@ {{ block.super }} $("#param-table").inventreeTable({ - url: "{% url 'api-part-param-template-list' %}", + url: "{% url 'api-part-parameter-template-list' %}", queryParams: { ordering: 'name', }, @@ -125,4 +143,8 @@ }); }); + $("#import-part").click(function() { + launchModalForm("{% url 'api-part-import' %}?reset", {}); + }); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/templates/attachment_table.html b/InvenTree/templates/attachment_table.html index 35b114cc05..18a4da9acc 100644 --- a/InvenTree/templates/attachment_table.html +++ b/InvenTree/templates/attachment_table.html @@ -10,35 +10,6 @@
                - - - - - - - - - - {% for attachment in attachments %} - - - - - - - {% endfor %} - +
                {% trans "File" %}{% trans "Comment" %}{% trans "Uploaded" %}
                {{ attachment.basename }}{{ attachment.comment }} - {% if attachment.upload_date %}{{ attachment.upload_date }}{% endif %} - {% if attachment.user %}{{ attachment.user.username }}{% endif %} - -
                - - -
                -
                \ No newline at end of file diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 65712b7394..9d4eaa5142 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -40,8 +40,7 @@ - - + @@ -136,7 +135,7 @@ - + @@ -144,25 +143,29 @@ - + + + + - - + + + + + + + - - - - diff --git a/InvenTree/InvenTree/static/script/inventree/api.js b/InvenTree/templates/js/api.js similarity index 60% rename from InvenTree/InvenTree/static/script/inventree/api.js rename to InvenTree/templates/js/api.js index b43bcc8419..8169671836 100644 --- a/InvenTree/InvenTree/static/script/inventree/api.js +++ b/InvenTree/templates/js/api.js @@ -1,5 +1,16 @@ +{% load i18n %} +{% load inventree_extras %} + var jQuery = window.$; +$.urlParam = function(name){ + var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); + if (results==null) { + return null; + } + return decodeURI(results[1]) || 0; +} + // using jQuery function getCookie(name) { var cookieValue = null; @@ -18,7 +29,15 @@ function getCookie(name) { } function inventreeGet(url, filters={}, options={}) { + + // Middleware token required for data update + //var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); + var csrftoken = getCookie('csrftoken'); + return $.ajax({ + beforeSend: function(xhr, settings) { + xhr.setRequestHeader('X-CSRFToken', csrftoken); + }, url: url, type: 'GET', data: filters, @@ -103,10 +122,11 @@ function inventreePut(url, data={}, options={}) { } }, error: function(xhr, ajaxOptions, thrownError) { - console.error('Error on UPDATE to ' + url); - console.error(thrownError); if (options.error) { options.error(xhr, ajaxOptions, thrownError); + } else { + console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`); + console.error(thrownError); } }, complete: function(xhr, status) { @@ -129,4 +149,49 @@ function inventreeDelete(url, options={}) { inventreePut(url, {}, options); +} + + +function showApiError(xhr) { + + var title = null; + var message = null; + + switch (xhr.status) { + case 0: // No response + title = '{% trans "No Response" %}'; + message = '{% trans "No response from the InvenTree server" %}'; + break; + case 400: // Bad request + // Note: Normally error code 400 is handled separately, + // and should now be shown here! + title = '{% trans "Error 400: Bad request" %}'; + message = '{% trans "API request returned error code 400" %}'; + break; + case 401: // Not authenticated + title = '{% trans "Error 401: Not Authenticated" %}'; + message = '{% trans "Authentication credentials not supplied" %}'; + break; + case 403: // Permission denied + title = '{% trans "Error 403: Permission Denied" %}'; + message = '{% trans "You do not have the required permissions to access this function" %}'; + break; + case 404: // Resource not found + title = '{% trans "Error 404: Resource Not Found" %}'; + message = '{% trans "The requested resource could not be located on the server" %}'; + break; + case 408: // Timeout + title = '{% trans "Error 408: Timeout" %}'; + message = '{% trans "Connection timeout while requesting data from server" %}'; + break; + default: + title = '{% trans "Unhandled Error Code" %}'; + message = `{% trans "Error code" %}: ${xhr.status}`; + break; + } + + message += "
                "; + message += renderErrorMessage(xhr); + + showAlertDialog(title, message); } \ No newline at end of file diff --git a/InvenTree/templates/js/attachment.js b/InvenTree/templates/js/attachment.js new file mode 100644 index 0000000000..4b9d522a59 --- /dev/null +++ b/InvenTree/templates/js/attachment.js @@ -0,0 +1,86 @@ +{% load i18n %} + +function reloadAttachmentTable() { + + $('#attachment-table').bootstrapTable("refresh"); +} + + +function loadAttachmentTable(url, options) { + + var table = options.table || '#attachment-table'; + + $(table).inventreeTable({ + url: url, + name: options.name || 'attachments', + formatNoMatches: function() { return '{% trans "No attachments found" %}'}, + sortable: true, + search: false, + queryParams: options.filters || {}, + onPostBody: function() { + // Add callback for 'edit' button + $(table).find('.button-attachment-edit').click(function() { + var pk = $(this).attr('pk'); + + if (options.onEdit) { + options.onEdit(pk); + } + }); + + // Add callback for 'delete' button + $(table).find('.button-attachment-delete').click(function() { + var pk = $(this).attr('pk'); + + if (options.onDelete) { + options.onDelete(pk); + } + }); + }, + columns: [ + { + field: 'attachment', + title: '{% trans "File" %}', + formatter: function(value, row) { + + var split = value.split('/'); + + return renderLink(split[split.length - 1], value); + } + }, + { + field: 'comment', + title: '{% trans "Comment" %}', + }, + { + field: 'upload_date', + title: '{% trans "Upload Date" %}', + }, + { + field: 'actions', + formatter: function(value, row) { + var html = ''; + + html = `
                `; + + html += makeIconButton( + 'fa-edit icon-blue', + 'button-attachment-edit', + row.pk, + '{% trans "Edit attachment" %}', + ); + + html += makeIconButton( + 'fa-trash-alt icon-red', + 'button-attachment-delete', + row.pk, + '{% trans "Delete attachment" %}', + ); + + html += `
                `; + + return html; + } + } + ] + }); +} \ No newline at end of file diff --git a/InvenTree/templates/js/bom.js b/InvenTree/templates/js/bom.js index 7328bcb331..32166d972a 100644 --- a/InvenTree/templates/js/bom.js +++ b/InvenTree/templates/js/bom.js @@ -242,7 +242,7 @@ function loadBomTable(table, options) { return renderLink(text, url); } }); - + cols.push( { field: 'purchase_price_range', @@ -259,26 +259,19 @@ function loadBomTable(table, options) { sortable: true, }); - /* - - // TODO - Re-introduce the pricing column at a later stage, - // once the pricing has been "fixed" - // O.W. 2020-11-24 - cols.push( { field: 'price_range', - title: '{% trans "Price" %}', + title: '{% trans "Buy Price" %}', sortable: true, formatter: function(value, row, index, field) { if (value) { return value; } else { - return "{% trans "No pricing available" %}"; + return "{% trans 'No pricing available' %}"; } } }); - */ cols.push({ field: 'optional', @@ -521,14 +514,13 @@ function loadBomTable(table, options) { var pk = $(this).attr('pk'); var url = `/part/bom/${pk}/delete/`; - launchModalForm( - url, - { - success: function() { - reloadBomTable(table); - } + constructForm(`/api/bom/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete BOM Item" %}', + onSuccess: function() { + reloadBomTable(table); } - ); + }); }); table.on('click', '.bom-edit-button', function() { diff --git a/InvenTree/templates/js/build.js b/InvenTree/templates/js/build.js index 3e5e438add..f43de6ec2b 100644 --- a/InvenTree/templates/js/build.js +++ b/InvenTree/templates/js/build.js @@ -1,34 +1,72 @@ {% load i18n %} {% load inventree_extras %} + +function buildFormFields() { + return { + reference: { + prefix: "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}", + }, + title: {}, + part: {}, + quantity: {}, + parent: { + filters: { + part_detail: true, + } + }, + batch: {}, + target_date: {}, + take_from: {}, + destination: {}, + link: { + icon: 'fa-link', + }, + issued_by: { + icon: 'fa-user', + }, + responsible: { + icon: 'fa-users', + }, + }; +} + + +function editBuildOrder(pk, options={}) { + + var fields = buildFormFields(); + + constructForm(`/api/build/${pk}/`, { + fields: fields, + reload: true, + title: '{% trans "Edit Build Order" %}', + }); +} + function newBuildOrder(options={}) { /* Launch modal form to create a new BuildOrder. */ - launchModalForm( - "{% url 'build-create' %}", - { - follow: true, - data: options.data || {}, - callback: [ - { - field: 'part', - action: function(value) { - inventreeGet( - `/api/part/${value}/`, {}, - { - success: function(response) { + var fields = buildFormFields(); - //enableField('serial_numbers', response.trackable); - //clearField('serial_numbers'); - } - } - ); - }, - } - ], - } - ) + if (options.part) { + fields.part.value = options.part; + } + + if (options.quantity) { + fields.quantity.value = options.quantity; + } + + if (options.parent) { + fields.parent.value = options.parent; + } + + constructForm(`/api/build/`, { + fields: fields, + follow: true, + method: 'POST', + title: '{% trans "Create Build Order" %}' + }); } @@ -231,6 +269,7 @@ function loadBuildOrderAllocationTable(table, options={}) { { field: 'quantity', title: '{% trans "Quantity" %}', + sortable: true, } ] }); @@ -383,14 +422,10 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { var idx = $(this).closest('tr').attr('data-index'); var row = $(table).bootstrapTable('getData')[idx]; - // Launch form to create a new build order - launchModalForm('{% url "build-create" %}', { - follow: true, - data: { - part: pk, - parent: buildId, - quantity: requiredQuantity(row) - sumAllocations(row), - } + newBuildOrder({ + part: pk, + parent: buildId, + quantity: requiredQuantity(row) - sumAllocations(row), }); }); @@ -875,6 +910,36 @@ function loadBuildTable(table, options) { title: '{% trans "Created" %}', sortable: true, }, + { + field: 'issued_by', + title: '{% trans "Issued by" %}', + sortable: true, + formatter: function(value, row, index, field) { + if (value) + { + return row.issued_by_detail.username; + } + else + { + return `{% trans "No user information" %}`; + } + } + }, + { + field: 'responsible', + title: '{% trans "Resposible" %}', + sortable: true, + formatter: function(value, row, index, field) { + if (value) + { + return row.responsible_detail.name; + } + else + { + return '{% trans "No information" %}'; + } + } + }, { field: 'target_date', title: '{% trans "Target Date" %}', @@ -1061,13 +1126,9 @@ function loadBuildPartsTable(table, options={}) { var idx = $(this).closest('tr').attr('data-index'); var row = $(table).bootstrapTable('getData')[idx]; - // Launch form to create a new build order - launchModalForm('{% url "build-create" %}', { - follow: true, - data: { - part: pk, - parent: options.build, - } + newBuildOrder({ + part: pk, + parent: options.build, }); }); } diff --git a/InvenTree/templates/js/company.js b/InvenTree/templates/js/company.js index 078b40f4b9..b202fbcd52 100644 --- a/InvenTree/templates/js/company.js +++ b/InvenTree/templates/js/company.js @@ -1,5 +1,210 @@ {% load i18n %} + +function manufacturerPartFields() { + + return { + part: {}, + manufacturer: {}, + MPN: { + icon: 'fa-hashtag', + }, + description: {}, + link: { + icon: 'fa-link', + } + }; +} + + +function createManufacturerPart(options={}) { + + var fields = manufacturerPartFields(); + + if (options.part) { + fields.part.value = options.part; + fields.part.hidden = true; + } + + if (options.manufacturer) { + fields.manufacturer.value = options.manufacturer; + } + + constructForm('{% url "api-manufacturer-part-list" %}', { + fields: fields, + method: 'POST', + title: '{% trans "Add Manufacturer Part" %}', + onSuccess: options.onSuccess + }); +} + + +function editManufacturerPart(part, options={}) { + + var url = `/api/company/part/manufacturer/${part}/`; + + constructForm(url, { + fields: manufacturerPartFields(), + title: '{% trans "Edit Manufacturer Part" %}', + onSuccess: options.onSuccess + }); +} + +function deleteManufacturerPart(part, options={}) { + + constructForm(`/api/company/part/manufacturer/${part}/`, { + method: 'DELETE', + title: '{% trans "Delete Manufacturer Part" %}', + onSuccess: options.onSuccess, + }); +} + + +function supplierPartFields() { + + return { + part: {}, + supplier: {}, + SKU: { + icon: 'fa-hashtag', + }, + manufacturer_part: { + filters: { + part_detail: true, + manufacturer_detail: true, + } + }, + description: {}, + link: { + icon: 'fa-link', + }, + note: { + icon: 'fa-pencil-alt', + }, + packaging: { + icon: 'fa-box', + } + }; +} + +/* + * Launch a form to create a new ManufacturerPart + */ +function createSupplierPart(options={}) { + + var fields = supplierPartFields(); + + if (options.part) { + fields.manufacturer_part.filters.part = options.part; + fields.part.hidden = true; + fields.part.value = options.part; + } + + if (options.supplier) { + fields.supplier.value = options.supplier; + } + + if (options.manufacturer_part) { + fields.manufacturer_part.value = options.manufacturer_part; + } + + constructForm('{% url "api-supplier-part-list" %}', { + fields: fields, + method: 'POST', + title: '{% trans "Add Supplier Part" %}', + onSuccess: options.onSuccess, + }); +} + + +function editSupplierPart(part, options={}) { + + constructForm(`/api/company/part/${part}/`, { + fields: supplierPartFields(), + title: '{% trans "Edit Supplier Part" %}', + onSuccess: options.onSuccess + }); +} + + +function deleteSupplierPart(part, options={}) { + + constructForm(`/api/company/part/${part}/`, { + method: 'DELETE', + title: '{% trans "Delete Supplier Part" %}', + onSuccess: options.onSuccess, + }); +} + + +// Returns a default form-set for creating / editing a Company object +function companyFormFields(options={}) { + + return { + name: {}, + description: {}, + website: { + icon: 'fa-globe', + }, + address: { + icon: 'fa-envelope', + }, + currency: { + icon: 'fa-dollar-sign', + }, + phone: { + icon: 'fa-phone', + }, + email: { + icon: 'fa-at', + }, + contact: { + icon: 'fa-address-card', + }, + is_supplier: {}, + is_manufacturer: {}, + is_customer: {} + }; +} + + +function editCompany(pk, options={}) { + + var fields = options.fields || companyFormFields(); + + constructForm( + `/api/company/${pk}/`, + { + method: 'PATCH', + fields: fields, + reload: true, + title: '{% trans "Edit Company" %}', + } + ); +}; + +/* + * Launches a form to create a new company. + * As this can be called from many different contexts, + * we abstract it here! + */ +function createCompany(options={}) { + + // Default field set + var fields = options.fields || companyFormFields(); + + constructForm( + '{% url "api-company-list" %}', + { + method: 'POST', + fields: fields, + follow: true, + title: '{% trans "Add new Company" %}', + } + ); +} + + function loadCompanyTable(table, url, options={}) { /* * Load company listing data into specified table. @@ -101,6 +306,61 @@ function loadCompanyTable(table, url, options={}) { } +function deleteManufacturerParts(selections, options={}) { + + if (selections.length == 0) { + return; + } + + var parts = []; + + var text = ` +
                +

                {% trans "The following manufacturer parts will be deleted" %}:

                +
                  `; + + selections.forEach(function(item) { + parts.push(item.pk); + + text += ` +
                • +

                  ${item.MPN} - ${item.part_detail.full_name}

                  +
                • `; + }); + + text += ` +
                +
                `; + + showQuestionDialog( + '{% trans "Delete Manufacturer Parts" %}', + text, + { + accept_text: '{% trans "Delete" %}', + accept: function() { + + // Delete each manufacturer part + var requests = []; + + parts.forEach(function(pk) { + var url = `/api/company/part/manufacturer/${pk}`; + + requests.push(inventreeDelete(url)); + }); + + // Wait for all the requests to complete + $.when.apply($, requests).then(function() { + + if (options.onSuccess) { + options.onSuccess(); + } + }) + } + } + ); +} + + function loadManufacturerPartTable(table, url, options) { /* * Load manufacturer part table @@ -194,7 +454,57 @@ function loadManufacturerPartTable(table, url, options) { } } }, + { + field: 'description', + title: '{% trans "Description" %}', + sortable: false, + switchable: true, + }, + { + field: 'actions', + title: '', + sortable: false, + switchable: false, + formatter: function(value, row) { + var pk = row.pk; + + var html = `
                `; + + html += makeIconButton('fa-edit icon-blue', 'button-manufacturer-part-edit', pk, '{% trans "Edit manufacturer part" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-manufacturer-part-delete', pk, '{% trans "Delete manufacturer part" %}'); + + html += '
                '; + + return html; + } + } ], + onPostBody: function() { + // Callbacks + $(table).find('.button-manufacturer-part-edit').click(function() { + var pk = $(this).attr('pk'); + + editManufacturerPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + + $(table).find('.button-manufacturer-part-delete').click(function() { + var pk = $(this).attr('pk'); + + deleteManufacturerPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }) + } }); } @@ -228,7 +538,7 @@ function loadManufacturerPartParameterTable(table, url, options) { { checkbox: true, switchable: false, - visible: false, + visible: true, }, { field: 'name', @@ -273,27 +583,28 @@ function loadManufacturerPartParameterTable(table, url, options) { $(table).find('.button-parameter-edit').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/manufacturer-part/parameter/${pk}/edit/`, - { - success: function() { - $(table).bootstrapTable('refresh'); - } + constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, { + fields: { + name: {}, + value: {}, + units: {}, + }, + title: '{% trans "Edit Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); } - ); - + }); }); $(table).find('.button-parameter-delete').click(function() { var pk = $(this).attr('pk'); - launchModalForm( - `/manufacturer-part/parameter/${pk}/delete/`, - { - success: function() { - $(table).bootstrapTable('refresh'); - } + constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); } - ); + }); }); } }); @@ -408,7 +719,7 @@ function loadSupplierPartTable(table, url, options) { title: '{% trans "MPN" %}', formatter: function(value, row, index, field) { if (value && row.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.manufacturer_part.pk}/`); + return renderLink(value, `/manufacturer-part/${row.manufacturer_part}/`); } else { return "-"; } @@ -425,6 +736,65 @@ function loadSupplierPartTable(table, url, options) { } } }, + { + field: 'description', + title: '{% trans "Description" %}', + sortable: false, + }, + { + field: 'note', + title: '{% trans "Notes" %}', + sortable: false, + }, + { + field: 'packaging', + title: '{% trans "Packaging" %}', + sortable: false, + }, + { + field: 'actions', + title: '', + sortable: false, + switchable: false, + formatter: function(value, row) { + var pk = row.pk; + + var html = `
                `; + + html += makeIconButton('fa-edit icon-blue', 'button-supplier-part-edit', pk, '{% trans "Edit supplier part" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-supplier-part-delete', pk, '{% trans "Delete supplier part" %}'); + + html += '
                '; + + return html; + } + } ], + onPostBody: function() { + // Callbacks + $(table).find('.button-supplier-part-edit').click(function() { + var pk = $(this).attr('pk'); + + editSupplierPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + + $(table).find('.button-supplier-part-delete').click(function() { + var pk = $(this).attr('pk'); + + deleteSupplierPart( + pk, + { + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }) + } }); } \ No newline at end of file diff --git a/InvenTree/templates/js/filters.js b/InvenTree/templates/js/filters.js index a27e91d5dc..4ee08affdf 100644 --- a/InvenTree/templates/js/filters.js +++ b/InvenTree/templates/js/filters.js @@ -314,7 +314,7 @@ function setupFilterList(tableKey, table, target) { // Only add the new filter if it is not empty! if (tag && tag.length > 0) { var filters = addTableFilter(tableKey, tag, val); - reloadTable(table, filters); + reloadTableFilters(table, filters); // Run this function again setupFilterList(tableKey, table, target); @@ -333,7 +333,7 @@ function setupFilterList(tableKey, table, target) { element.find(`#${clear}`).click(function() { var filters = clearTableFilters(tableKey); - reloadTable(table, filters); + reloadTableFilters(table, filters); setupFilterList(tableKey, table, target); }); @@ -346,7 +346,7 @@ function setupFilterList(tableKey, table, target) { var filters = removeTableFilter(tableKey, filter); - reloadTable(table, filters); + reloadTableFilters(table, filters); // Run this function again! setupFilterList(tableKey, table, target); diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js new file mode 100644 index 0000000000..587ea07a16 --- /dev/null +++ b/InvenTree/templates/js/forms.js @@ -0,0 +1,1668 @@ +{% load i18n %} +{% load inventree_extras %} + +/** + * + * This file contains code for rendering (and managing) HTML forms + * which are served via the django-drf API. + * + * The django DRF library provides an OPTIONS method for each API endpoint, + * which allows us to introspect the available fields at any given endpoint. + * + * The OPTIONS method provides the following information for each available field: + * + * - Field name + * - Field label (translated) + * - Field help text (translated) + * - Field type + * - Read / write status + * - Field required status + * - min_value / max_value + * + */ + +/* + * Return true if the OPTIONS specify that the user + * can perform a GET method at the endpoint. + */ +function canView(OPTIONS) { + + if ('actions' in OPTIONS) { + return ('GET' in OPTIONS.actions); + } else { + return false; + } +} + + +/* + * Return true if the OPTIONS specify that the user + * can perform a POST method at the endpoint + */ +function canCreate(OPTIONS) { + + if ('actions' in OPTIONS) { + return ('POST' in OPTIONS.actions); + } else { + return false; + } +} + + +/* + * Return true if the OPTIONS specify that the user + * can perform a PUT or PATCH method at the endpoint + */ +function canChange(OPTIONS) { + + if ('actions' in OPTIONS) { + return ('PUT' in OPTIONS.actions || 'PATCH' in OPTIONS.actions); + } else { + return false; + } +} + + +/* + * Return true if the OPTIONS specify that the user + * can perform a DELETE method at the endpoint + */ +function canDelete(OPTIONS) { + + if ('actions' in OPTIONS) { + return ('DELETE' in OPTIONS.actions); + } else { + return false; + } +} + + +/* + * Get the API endpoint options at the provided URL, + * using a HTTP options request. + */ +function getApiEndpointOptions(url, callback, options) { + + // Return the ajax request object + $.ajax({ + url: url, + type: 'OPTIONS', + contentType: 'application/json', + dataType: 'json', + accepts: { + json: 'application/json', + }, + success: callback, + error: function(request, status, error) { + // TODO: Handle error + console.log(`ERROR in getApiEndpointOptions at '${url}'`); + } + }); +} + + +/* + * Construct a 'creation' (POST) form, to create a new model in the database. + * + * arguments: + * - fields: The 'actions' object provided by the OPTIONS endpoint + * + * options: + * - + */ +function constructCreateForm(fields, options) { + + // Check if default values were provided for any fields + for (const name in fields) { + + var field = fields[name]; + + var field_options = options.fields[name] || {}; + + // If a 'value' is not provided for the field, + if (field.value == null) { + + if ('value' in field_options) { + // Client has specified the default value for the field + field.value = field_options.value; + } else if (field.default != null) { + // OPTIONS endpoint provided default value for this field + field.value = field.default; + } + } + } + + // We should have enough information to create the form! + constructFormBody(fields, options); +} + + +/* + * Construct a 'change' (PATCH) form, to create a new model in the database. + * + * arguments: + * - fields: The 'actions' object provided by the OPTIONS endpoint + * + * options: + * - + */ +function constructChangeForm(fields, options) { + + // Request existing data from the API endpoint + $.ajax({ + url: options.url, + type: 'GET', + contentType: 'application/json', + dataType: 'json', + accepts: { + json: 'application/json', + }, + success: function(data) { + + // Push existing 'value' to each field + for (const field in data) { + + if (field in fields) { + fields[field].value = data[field]; + } + } + + // Store the entire data object + options.instance = data; + + constructFormBody(fields, options); + }, + error: function(request, status, error) { + // TODO: Handle error here + console.log(`ERROR in constructChangeForm at '${options.url}'`); + } + }); +} + + +/* + * Construct a 'delete' form, to remove a model instance from the database. + * + * arguments: + * - fields: The 'actions' object provided by the OPTIONS request + * - options: The 'options' object provided by the client + */ +function constructDeleteForm(fields, options) { + + // Force the "confirm" property if not set + if (!('confirm' in options)) { + options.confirm = true; + } + + // Request existing data from the API endpoint + // This data can be used to render some information on the form + $.ajax({ + url: options.url, + type: 'GET', + contentType: 'application/json', + dataType: 'json', + accepts: { + json: 'application/json', + }, + success: function(data) { + + // Store the instance data + options.instance = data; + + constructFormBody(fields, options); + }, + error: function(request, status, error) { + // TODO: Handle error here + console.log(`ERROR in constructDeleteForm at '${options.url}`); + } + }); +} + + +/* + * Request API OPTIONS data from the server, + * and construct a modal form based on the response. + * + * url: API URL which defines form data + * options: + * - method: The HTTP method e.g. 'PUT', 'POST', 'DELETE' (default='PATCH') + * - title: The form title + * - submitText: Text for the "submit" button + * - closeText: Text for the "close" button + * - fields: list of fields to display, with the following options + * - filters: API query filters + * - onEdit: callback when field is edited + * - secondary: Define a secondary modal form for this field + * - label: Specify custom label + * - help_text: Specify custom help_text + * - placeholder: Specify custom placeholder text + * - value: Specify initial value + * - hidden: Set to true to hide the field + * - icon: font-awesome icon to display before the field + * - prefix: Custom HTML prefix to display before the field + * - focus: Name of field to focus on when modal is displayed + * - preventClose: Set to true to prevent form from closing on success + * - onSuccess: callback function when form action is successful + * - follow: If a 'url' is provided by the API on success, redirect to it + * - redirect: A URL to redirect to after form success + * - reload: Set to true to reload the current page after form success + * - confirm: Set to true to require a "confirm" button + * - confirmText: Text for confirm button (default = "Confirm") + * + */ +function constructForm(url, options) { + + // An "empty" form will be defined locally + if (url == null) { + constructFormBody({}, options); + } + + // Save the URL + options.url = url; + + // Default HTTP method + options.method = options.method || 'PATCH'; + + // Request OPTIONS endpoint from the API + getApiEndpointOptions(url, function(OPTIONS) { + + /* + * Determine what "type" of form we want to construct, + * based on the requested action. + * + * First we must determine if the user has the correct permissions! + */ + + switch (options.method) { + case 'POST': + if (canCreate(OPTIONS)) { + constructCreateForm(OPTIONS.actions.POST, options); + } else { + // User does not have permission to POST to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Create operation not allowed" %}' + ); + console.log(`'POST action unavailable at ${url}`); + } + break; + case 'PUT': + case 'PATCH': + if (canChange(OPTIONS)) { + constructChangeForm(OPTIONS.actions.PUT, options); + } else { + // User does not have permission to PUT/PATCH to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Update operation not allowed" %}' + ); + console.log(`${options.method} action unavailable at ${url}`); + } + break; + case 'DELETE': + if (canDelete(OPTIONS)) { + constructDeleteForm(OPTIONS.actions.DELETE, options); + } else { + // User does not have permission to DELETE to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Delete operation not allowed" %}' + ); + console.log(`DELETE action unavailable at ${url}`); + } + break; + case 'GET': + if (canView(OPTIONS)) { + // TODO? + } else { + // User does not have permission to GET to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "View operation not allowed" %}' + ); + console.log(`GET action unavailable at ${url}`); + } + break; + default: + console.log(`constructForm() called with invalid method '${options.method}'`); + break; + } + }); +} + + +/* + * Construct a modal form based on the provided options + * + * arguments: + * - fields: The endpoint description returned from the OPTIONS request + * - options: form options object provided by the client. + */ +function constructFormBody(fields, options) { + + var html = ''; + + // Client must provide set of fields to be displayed, + // otherwise *all* fields will be displayed + var displayed_fields = options.fields || fields; + + // Provide each field object with its own name + for(field in fields) { + fields[field].name = field; + + var field_options = displayed_fields[field]; + + // Copy custom options across to the fields object + if (field_options) { + + // Override existing query filters (if provided!) + fields[field].filters = Object.assign(fields[field].filters || {}, field_options.filters); + + // TODO: Refactor the following code with Object.assign (see above) + + // Secondary modal options + fields[field].secondary = field_options.secondary; + + // Edit callback + fields[field].onEdit = field_options.onEdit; + + fields[field].multiline = field_options.multiline; + + // Custom help_text + if (field_options.help_text) { + fields[field].help_text = field_options.help_text; + } + + // Custom label + if (field_options.label) { + fields[field].label = field_options.label; + } + + // Custom placeholder + if (field_options.placeholder) { + fields[field].placeholder = field_options.placeholder; + } + + // Choices + if (field_options.choices) { + fields[field].choices = field_options.choices; + } + + // Field prefix + if (field_options.prefix) { + fields[field].prefix = field_options.prefix; + } else if (field_options.icon) { + // Specify icon like 'fa-user' + fields[field].prefix = ``; + } + + fields[field].hidden = field_options.hidden; + + if (field_options.read_only != null) { + fields[field].read_only = field_options.read_only; + } + } + } + + // Construct an ordered list of field names + var field_names = []; + + for (var name in displayed_fields) { + + field_names.push(name); + + // Field not specified in the API, but the client wishes to add it! + if (!(name in fields)) { + fields[name] = displayed_fields[name]; + } + } + + // Push the ordered field names into the options, + // allowing successive functions to access them. + options.field_names = field_names; + + // Render selected fields + + for (var idx = 0; idx < field_names.length; idx++) { + + var name = field_names[idx]; + + var field = fields[name]; + + switch (field.type) { + // Skip field types which are simply not supported + case 'nested object': + continue; + default: + break; + } + + html += constructField(name, field, options); + } + + // TODO: Dynamically create the modals, + // so that we can have an infinite number of stacks! + + // Create a new modal if one does not exists + if (!options.modal) { + options.modal = createNewModal(options); + } + + var modal = options.modal; + + modalEnable(modal, true); + + // Insert generated form content + $(modal).find('#form-content').html(html); + + if (options.preFormContent) { + $(modal).find('#pre-form-content').html(options.preFormContent); + } + + if (options.postFormContent) { + $(modal).find('#post-form-content').html(options.postFormContent); + } + + // Clear any existing buttons from the modal + $(modal).find('#modal-footer-buttons').html(''); + + // Insert "confirm" button (if required) + if (options.confirm) { + insertConfirmButton(options); + } + + // Display the modal + $(modal).modal('show'); + + updateFieldValues(fields, options); + + // Setup related fields + initializeRelatedFields(fields, options); + + // Attach edit callbacks (if required) + addFieldCallbacks(fields, options); + + // Attach clear callbacks (if required) + addClearCallbacks(fields, options); + + attachToggle(modal); + + $(modal + ' .select2-container').addClass('select-full-width'); + $(modal + ' .select2-container').css('width', '100%'); + + modalShowSubmitButton(modal, true); + + $(modal).on('click', '#modal-form-submit', function() { + + // Immediately disable the "submit" button, + // to prevent the form being submitted multiple times! + $(options.modal).find('#modal-form-submit').prop('disabled', true); + + // Run custom code before normal form submission + if (options.beforeSubmit) { + options.beforeSubmit(fields, options); + } + + // Run custom code instead of normal form submission + if (options.onSubmit) { + options.onSubmit(fields, options); + } else { + submitFormData(fields, options); + } + }); +} + + +// Add a "confirm" checkbox to the modal +// The "submit" button will be disabled unless "confirm" is checked +function insertConfirmButton(options) { + + var message = options.confirmMessage || '{% trans "Confirm" %}'; + + var confirm = ` + + ${message} + + `; + + $(options.modal).find('#modal-footer-buttons').append(confirm); + + // Disable the 'submit' button + $(options.modal).find('#modal-form-submit').prop('disabled', true); + + // Trigger event + $(options.modal).find('#modal-confirm').change(function() { + var enabled = this.checked; + + $(options.modal).find('#modal-form-submit').prop('disabled', !enabled); + }); +} + + +/* + * Submit form data to the server. + * + */ +function submitFormData(fields, options) { + + // Form data to be uploaded to the server + // Only used if file / image upload is required + var form_data = new FormData(); + + var data = {}; + + var has_files = false; + + // Extract values for each field + options.field_names.forEach(function(name) { + + var field = fields[name] || null; + + if (field) { + + var value = getFormFieldValue(name, field, options); + + // Handle file inputs + if (field.type == 'image upload' || field.type == 'file upload') { + + var field_el = $(options.modal).find(`#id_${name}`)[0]; + + var field_files = field_el.files; + + if (field_files.length > 0) { + // One file per field, please! + var file = field_files[0]; + + form_data.append(name, file); + + has_files = true; + } + } else { + + // Normal field (not a file or image) + form_data.append(name, value); + + data[name] = value; + } + } else { + console.log(`WARNING: Could not find field matching '${name}'`); + } + }); + + var upload_func = inventreePut; + + if (has_files) { + upload_func = inventreeFormDataUpload; + data = form_data; + } + + // Submit data + upload_func( + options.url, + data, + { + method: options.method, + success: function(response, status) { + handleFormSuccess(response, options); + }, + error: function(xhr, status, thrownError) { + + switch (xhr.status) { + case 400: // Bad request + handleFormErrors(xhr.responseJSON, fields, options); + break; + default: + $(options.modal).modal('hide'); + showApiError(xhr); + break; + } + } + } + ); +} + + +/* + * Update (set) the field values based on the specified data. + * + * Iterate through each of the displayed fields, + * and set the 'val' attribute of each one. + * + */ +function updateFieldValues(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name] || null; + + if (field == null) { continue; } + + var value = field.value; + + if (value == null) { + value = field.default; + } + + if (value == null) { continue; } + + updateFieldValue(name, value, field, options); + } +} + + +function updateFieldValue(name, value, field, options) { + var el = $(options.modal).find(`#id_${name}`); + + switch (field.type) { + case 'boolean': + el.prop('checked', value); + break; + case 'related field': + // Clear? + if (value == null && !field.required) { + el.val(null).trigger('change'); + } + // TODO - Specify an actual value! + break; + case 'file upload': + case 'image upload': + break; + default: + el.val(value); + break; + } +} + + +/* + * Extract and field value before sending back to the server + * + * arguments: + * - name: The name of the field + * - field: The field specification provided from the OPTIONS request + * - options: The original options object provided by the client + */ +function getFormFieldValue(name, field, options) { + + // Find the HTML element + var el = $(options.modal).find(`#id_${name}`); + + if (!el) { + return null; + } + + var value = null; + + switch (field.type) { + case 'boolean': + value = el.is(":checked"); + break; + case 'date': + case 'datetime': + value = el.val(); + + // Ensure empty values are sent as nulls + if (!value || value.length == 0) { + value = null; + } + break; + default: + value = el.val(); + break; + } + + return value; +} + + +/* + * Handle successful form posting + * + * arguments: + * - response: The JSON response object from the server + * - options: The original options object provided by the client + */ +function handleFormSuccess(response, options) { + + // Close the modal + if (!options.preventClose) { + // Note: The modal will be deleted automatically after closing + $(options.modal).modal('hide'); + } + + // Display any required messages + // Should we show alerts immediately or cache them? + var cache = (options.follow && response.url) || options.redirect || options.reload; + + // Display any messages + if (response && response.success) { + showAlertOrCache("alert-success", response.success, cache); + } + + if (response && response.info) { + showAlertOrCache("alert-info", response.info, cache); + } + + if (response && response.warning) { + showAlertOrCache("alert-warning", response.warning, cache); + } + + if (response && response.danger) { + showAlertOrCache("alert-danger", response.danger, cache); + } + + if (options.onSuccess) { + // Callback function + options.onSuccess(response, options); + } + + if (options.follow && response.url) { + // Follow the returned URL + window.location.href = response.url; + } else if (options.reload) { + // Reload the current page + location.reload(); + } else if (options.redirect) { + // Redirect to a specified URL + window.location.href = options.redirect; + } +} + + + +/* + * Remove all error text items from the form + */ +function clearFormErrors(options) { + + // Remove the individual error messages + $(options.modal).find('.form-error-message').remove(); + + // Remove the "has error" class + $(options.modal).find('.has-error').removeClass('has-error'); + + // Hide the 'non field errors' + $(options.modal).find('#non-field-errors').html(''); +} + + +/* + * Display form error messages as returned from the server. + * + * arguments: + * - errors: The JSON error response from the server + * - fields: The form data object + * - options: Form options provided by the client + */ +function handleFormErrors(errors, fields, options) { + + // Reset the status of the "submit" button + $(options.modal).find('#modal-form-submit').prop('disabled', false); + + // Remove any existing error messages from the form + clearFormErrors(options); + + var non_field_errors = $(options.modal).find('#non-field-errors'); + + non_field_errors.append( + `
                + {% trans "Form errors exist" %} +
                ` + ); + + // Non-field errors? + if ('non_field_errors' in errors) { + + var nfe = errors.non_field_errors; + + for (var idx = 0; idx < nfe.length; idx++) { + var err = nfe[idx]; + + var html = ` +
                + ${err} +
                `; + + non_field_errors.append(html); + } + } + + for (field_name in errors) { + + // Add the 'has-error' class + $(options.modal).find(`#div_id_${field_name}`).addClass('has-error'); + + var field_dom = $(options.modal).find(`#errors-${field_name}`); // $(options.modal).find(`#id_${field_name}`); + + var field_errors = errors[field_name]; + + // Add an entry for each returned error message + for (var idx = field_errors.length-1; idx >= 0; idx--) { + + var error_text = field_errors[idx]; + + var html = ` + + ${error_text} + `; + + field_dom.append(html); + } + } +} + + +/* + * Attach callbacks to specified fields, + * triggered after the field value is edited. + * + * Callback function is called with arguments (name, field, options) + */ +function addFieldCallbacks(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name]; + + if (!field || !field.onEdit) continue; + + addFieldCallback(name, field, options); + } +} + + +function addFieldCallback(name, field, options) { + + $(options.modal).find(`#id_${name}`).change(function() { + field.onEdit(name, field, options); + }); +} + + +function addClearCallbacks(fields, options) { + + for (var idx = 0; idx < options.field_names.length; idx++) { + + var name = options.field_names[idx]; + + var field = fields[name]; + + if (!field || field.required) continue; + + addClearCallback(name, field, options); + } +} + + +function addClearCallback(name, field, options) { + + $(options.modal).find(`#clear_${name}`).click(function() { + updateFieldValue(name, null, field, options); + }); +} + + +function initializeRelatedFields(fields, options) { + + var field_names = options.field_names; + + for (var idx = 0; idx < field_names.length; idx++) { + + var name = field_names[idx]; + + var field = fields[name] || null; + + if (!field || field.hidden) continue; + + switch (field.type) { + case 'related field': + initializeRelatedField(name, field, options); + break; + case 'choice': + initializeChoiceField(name, field, options); + break; + } + } +} + + +/* + * Add a button to launch a secondary modal, to create a new modal instance. + * + * arguments: + * - name: The name of the field + * - field: The field data object + * - options: The options object provided by the client + */ +function addSecondaryModal(name, field, options) { + + var secondary = field.secondary; + + var html = ` + +
                + ${secondary.label || secondary.title} +
                +
                `; + + $(options.modal).find(`label[for="id_${name}"]`).append(html); + + // TODO: Launch a callback + $(options.modal).find(`#btn-new-${name}`).click(function() { + + if (secondary.callback) { + // A "custom" callback can be specified for the button + secondary.callback(field, options); + } else if (secondary.api_url) { + // By default, a new modal form is created, with the parameters specified + // The parameters match the "normal" form creation parameters + + secondary.onSuccess = function(data, opts) { + setRelatedFieldData(name, data, options); + }; + + constructForm(secondary.api_url, secondary); + } + }); +} + + +/* + * Initializea single related-field + * + * argument: + * - modal: DOM identifier for the modal window + * - name: name of the field e.g. 'location' + * - field: Field definition from the OPTIONS request + * - options: Original options object provided by the client + */ +function initializeRelatedField(name, field, options) { + + if (!field.api_url) { + // TODO: Provide manual api_url option? + console.log(`Related field '${name}' missing 'api_url' parameter.`); + return; + } + + // Find the select element and attach a select2 to it + var select = $(options.modal).find(`#id_${name}`); + + // Add a button to launch a 'secondary' modal + if (field.secondary != null) { + addSecondaryModal(name, field, options); + } + + // TODO: Add 'placeholder' support for entry select2 fields + + // limit size for AJAX requests + var pageSize = options.pageSize || 25; + + select.select2({ + placeholder: '', + dropdownParent: $(options.modal), + dropdownAutoWidth: false, + ajax: { + url: field.api_url, + dataType: 'json', + delay: 250, + cache: true, + data: function(params) { + + if (!params.page) { + offset = 0; + } else { + offset = (params.page - 1) * pageSize; + } + + // Custom query filters can be specified against each field + var query = field.filters || {}; + + // Add search and pagination options + query.search = params.term; + query.offset = offset; + query.limit = pageSize; + + return query; + }, + processResults: function(response) { + // Convert the returned InvenTree data into select2-friendly format + + var data = []; + + var more = false; + + if ('count' in response && 'results' in response) { + // Response is paginated + data = response.results; + + // Any more data available? + if (response.next) { + more = true; + } + + } else { + // Non-paginated response + data = response; + } + + // Each 'row' must have the 'id' attribute + for (var idx = 0; idx < data.length; idx++) { + data[idx].id = data[idx].pk; + } + + // Ref: https://select2.org/data-sources/formats + var results = { + results: data, + pagination: { + more: more, + } + }; + + return results; + }, + }, + templateResult: function(item, container) { + + // Extract 'instance' data passed through from an initial value + // Or, use the raw 'item' data as a backup + var data = item; + + if (item.element && item.element.instance) { + data = item.element.instance; + } + + if (!data.pk) { + return $(searching()); + } + + // Custom formatting for the search results + if (field.model) { + // If the 'model' is specified, hand it off to the custom model render + var html = renderModelData(name, field.model, data, field, options); + return $(html); + } else { + // Return a simple renderering + console.log(`WARNING: templateResult() missing 'field.model' for '${name}'`); + return `${name} - ${item.id}`; + } + }, + templateSelection: function(item, container) { + + // Extract 'instance' data passed through from an initial value + // Or, use the raw 'item' data as a backup + var data = item; + + if (item.element && item.element.instance) { + data = item.element.instance; + } + + if (!data.pk) { + return field.placeholder || ''; + return $(searching()); + } + + // Custom formatting for selected item + if (field.model) { + // If the 'model' is specified, hand it off to the custom model render + var html = renderModelData(name, field.model, data, field, options); + return $(html); + } else { + // Return a simple renderering + console.log(`WARNING: templateSelection() missing 'field.model' for '${name}'`); + return `${name} - ${item.id}`; + } + } + }); + + // If a 'value' is already defined, grab the model info from the server + if (field.value) { + var pk = field.value; + var url = `${field.api_url}/${pk}/`.replace('//', '/'); + + inventreeGet(url, field.filters || {}, { + success: function(data) { + setRelatedFieldData(name, data, options); + } + }); + } +} + + +/* + * Set the value of a select2 instace for a "related field", + * e.g. with data returned from a secondary modal + * + * arguments: + * - name: The name of the field + * - data: JSON data representing the model instance + * - options: The modal form specifications + */ +function setRelatedFieldData(name, data, options) { + + var select = $(options.modal).find(`#id_${name}`); + + var option = new Option(name, data.pk, true, true); + + // Assign the JSON data to the 'instance' attribute, + // so we can access and render it later + option.instance = data; + + select.append(option).trigger('change'); + + select.trigger({ + type: 'select2:select', + params: { + data: data + } + }); +} + + +function initializeChoiceField(name, field, options) { + + var select = $(options.modal).find(`#id_${name}`); + + select.select2({ + dropdownAutoWidth: false, + dropdownParent: $(options.modal), + }); +} + + +// Render a 'no results' element +function searching() { + return `{% trans "Searching" %}...`; +} + +/* + * Render a "foreign key" model reference in a select2 instance. + * Allows custom rendering with access to the entire serialized object. + * + * arguments: + * - name: The name of the field e.g. 'location' + * - model: The name of the InvenTree model e.g. 'stockitem' + * - data: The JSON data representation of the modal instance (GET request) + * - parameters: The field definition (OPTIONS) request + * - options: Other options provided at time of modal creation by the client + */ +function renderModelData(name, model, data, parameters, options) { + + if (!data) { + return parameters.placeholder || ''; + } + + // TODO: Implement this function for various models + + var html = null; + + var renderer = null; + + // Find a custom renderer + switch (model) { + case 'company': + renderer = renderCompany; + break; + case 'stockitem': + renderer = renderStockItem; + break; + case 'stocklocation': + renderer = renderStockLocation; + break; + case 'part': + renderer = renderPart; + break; + case 'partcategory': + renderer = renderPartCategory; + break; + case 'partparametertemplate': + renderer = renderPartParameterTemplate; + break; + case 'manufacturerpart': + renderer = renderManufacturerPart; + break; + case 'supplierpart': + renderer = renderSupplierPart; + break; + case 'build': + renderer = renderBuild; + break; + case 'owner': + renderer = renderOwner; + break; + case 'user': + renderer = renderUser; + break; + default: + break; + } + + if (renderer != null) { + html = renderer(name, data, parameters, options); + } + + if (html != null) { + return html; + } else { + console.log(`ERROR: Rendering not implemented for model '${model}'`); + // Simple text rendering + return `${model} - ID ${data.id}`; + } +} + + +/* + * Construct a single form 'field' for rendering in a form. + * + * arguments: + * - name: The 'name' of the field + * - parameters: The field parameters supplied by the DRF OPTIONS method + * + * options: + * - + * + * The function constructs a fieldset which mostly replicates django "crispy" forms: + * + * - Field name + * - Field (depends on specified field type) + * - Field description (help text) + * - Field errors + */ +function constructField(name, parameters, options) { + + var field_name = `id_${name}`; + + // Hidden inputs are rendered without label / help text / etc + if (parameters.hidden) { + return constructHiddenInput(name, parameters, options); + } + + var form_classes = 'form-group'; + + if (parameters.errors) { + form_classes += ' has-error'; + } + + var html = `
                `; + + // Add a label + html += constructLabel(name, parameters); + + html += `
                `; + + // Does this input deserve "extra" decorators? + var extra = parameters.prefix != null; + + // Some fields can have 'clear' inputs associated with them + if (!parameters.required && !parameters.read_only) { + switch (parameters.type) { + case 'string': + case 'url': + case 'email': + case 'integer': + case 'float': + case 'decimal': + case 'related field': + case 'date': + extra = true; + break; + default: + break; + } + } + + if (extra) { + html += `
                `; + + if (parameters.prefix) { + html += `${parameters.prefix}`; + } + } + + html += constructInput(name, parameters, options); + + if (extra) { + + if (!parameters.required) { + html += ` + + + `; + } + + html += `
                `; // input-group + } + + // Div for error messages + html += `
                `; + + if (parameters.help_text) { + html += constructHelpText(name, parameters, options); + } + + html += `
                `; // controls + html += `
                `; // form-group + + return html; +} + + +/* + * Construct a 'label' div + * + * arguments: + * - name: The name of the field + * - required: Is this a required field? + */ +function constructLabel(name, parameters) { + + var label_classes = 'control-label'; + + if (parameters.required) { + label_classes += ' requiredField'; + } + + var html = ``; + + return html; +} + + +/* + * Construct a form input based on the field parameters + * + * arguments: + * - name: The name of the field + * - parameters: Field parameters returned by the OPTIONS method + * + */ +function constructInput(name, parameters, options) { + + var html = ''; + + var func = null; + + switch (parameters.type) { + case 'boolean': + func = constructCheckboxInput; + break; + case 'string': + case 'url': + case 'email': + func = constructTextInput; + break; + case 'integer': + case 'float': + case 'decimal': + func = constructNumberInput; + break; + case 'choice': + func = constructChoiceInput; + break; + case 'related field': + func = constructRelatedFieldInput; + break; + case 'image upload': + case 'file upload': + func = constructFileUploadInput; + break; + case 'date': + func = constructDateInput; + break; + default: + // Unsupported field type! + break; + } + + if (func != null) { + html = func(name, parameters, options); + } else { + console.log(`WARNING: Unhandled form field type: '${parameters.type}'`); + } + + return html; +} + + +// Construct a set of default input options which apply to all input types +function constructInputOptions(name, classes, type, parameters) { + + var opts = []; + + opts.push(`id='id_${name}'`); + + opts.push(`class='${classes}'`); + + opts.push(`name='${name}'`); + + opts.push(`type='${type}'`); + + // Read only? + if (parameters.read_only) { + opts.push(`readonly=''`); + } + + if (parameters.value != null) { + // Existing value? + opts.push(`value='${parameters.value}'`); + } else if (parameters.default != null) { + // Otherwise, a defualt value? + opts.push(`value='${parameters.default}'`); + } + + // Maximum input length + if (parameters.max_length != null) { + opts.push(`maxlength='${parameters.max_length}'`); + } + + // Minimum input length + if (parameters.min_length != null) { + opts.push(`minlength='${parameters.min_length}'`); + } + + // Maximum value + if (parameters.max_value != null) { + opts.push(`max='${parameters.max_value}'`); + } + + // Minimum value + if (parameters.min_value != null) { + opts.push(`min='${parameters.min_value}'`); + } + + // Field is required? + if (parameters.required) { + opts.push(`required=''`); + } + + // Custom mouseover title? + if (parameters.title != null) { + opts.push(`title='${parameters.title}'`); + } + + // Placeholder? + if (parameters.placeholder != null) { + opts.push(`placeholder='${parameters.placeholder}'`); + } + + if (parameters.multiline) { + return ``; + } else { + return ``; + } +} + + +// Construct a "hidden" input +function constructHiddenInput(name, parameters, options) { + + return constructInputOptions( + name, + 'hiddeninput', + 'hidden', + parameters + ); +} + + +// Construct a "checkbox" input +function constructCheckboxInput(name, parameters, options) { + + return constructInputOptions( + name, + 'checkboxinput', + 'checkbox', + parameters + ); +} + + +// Construct a "text" input +function constructTextInput(name, parameters, options) { + + var classes = ''; + var type = ''; + + switch (parameters.type) { + default: + classes = 'textinput textInput form-control'; + type = 'text'; + break; + case 'url': + classes = 'urlinput form-control'; + type = 'url'; + break; + case 'email': + classes = 'emailinput form-control'; + type = 'email'; + break; + } + + return constructInputOptions( + name, + classes, + type, + parameters + ); +} + + +// Construct a "number" field +function constructNumberInput(name, parameters, options) { + + return constructInputOptions( + name, + 'numberinput form-control', + 'number', + parameters + ); +} + + +// Construct a "choice" input +function constructChoiceInput(name, parameters, options) { + + var html = ``; + + return html; +} + + +/* + * Construct a "related field" input. + * This will create a "select" input which will then, (after form is loaded), + * be converted into a select2 input. + * This will then be served custom data from the API (as required)... + */ +function constructRelatedFieldInput(name, parameters, options) { + + var html = ``; + + // Don't load any options - they will be filled via an AJAX request + + return html; +} + + +/* + * Construct a field for file upload + */ +function constructFileUploadInput(name, parameters, options) { + + var cls = 'clearablefileinput'; + + if (parameters.required) { + cls = 'fileinput'; + } + + return constructInputOptions( + name, + cls, + 'file', + parameters + ); +} + + +/* + * Construct a field for a date input + */ +function constructDateInput(name, parameters, options) { + + return constructInputOptions( + name, + 'dateinput form-control', + 'date', + parameters + ); +} + + +/* + * Construct a 'help text' div based on the field parameters + * + * arguments: + * - name: The name of the field + * - parameters: Field parameters returned by the OPTIONS method + * + */ +function constructHelpText(name, parameters, options) { + + var html = `
                ${parameters.help_text}
                `; + + return html; +} \ No newline at end of file diff --git a/InvenTree/templates/js/label.js b/InvenTree/templates/js/label.js index dab9c6dcfa..dc9e8fa935 100644 --- a/InvenTree/templates/js/label.js +++ b/InvenTree/templates/js/label.js @@ -105,6 +105,61 @@ function printStockLocationLabels(locations, options={}) { } +function printPartLabels(parts, options={}) { + /** + * Print labels for the provided parts + */ + + if (parts.length == 0) { + showAlertDialog( + '{% trans "Select Parts" %}', + '{% trans "Part(s) must be selected before printing labels" %}', + ); + + return; + } + + // Request available labels from the server + inventreeGet( + '{% url "api-part-label-list" %}', + { + enabled: true, + parts: parts, + }, + { + success: function(response) { + + if (response.length == 0) { + showAlertDialog( + '{% trans "No Labels Found" %}', + '{% trans "No labels found which match the selected part(s)" %}', + ); + + return; + } + + // Select label to print + selectLabel( + response, + parts, + { + success: function(pk) { + var url = `/api/label/part/${pk}/print/?`; + + parts.forEach(function(part) { + url += `parts[]=${part}&`; + }); + + window.location.href = url; + } + } + ); + } + } + ); +} + + function selectLabel(labels, items, options={}) { /** * Present the user with the available labels, diff --git a/InvenTree/templates/js/modals.js b/InvenTree/templates/js/modals.js index 03893a47b8..4bcc31fffa 100644 --- a/InvenTree/templates/js/modals.js +++ b/InvenTree/templates/js/modals.js @@ -1,5 +1,120 @@ {% load i18n %} + +/* + * Create and display a new modal dialog + * + * options: + * - title: Form title to render + * - submitText: Text to render on 'submit' button (default = "Submit") + * - closeText: Text to render on 'close' button (default = "Cancel") + * - focus: Name of field to focus on after launching + */ +function createNewModal(options={}) { + + var id = 1; + + // Check out what modal forms are already being displayed + $('.inventree-modal').each(function() { + + var split = this.id.split('-'); + var modal_id = parseInt(split[2]); + + if (modal_id >= id) { + id = modal_id + 1; + } + }); + + var html = ` + + `; + + $('body').append(html); + + var modal_name = `#modal-form-${id}`; + + $(modal_name).on('shown.bs.modal', function() { + $(modal_name + ' .modal-form-content').scrollTop(0); + + if (options.focus) { + getFieldByName(modal_name, options.focus).focus(); + } + }); + + // Automatically remove the modal when it is deleted! + $(modal_name).on('hidden.bs.modal', function(e) { + $(modal_name).remove(); + }); + + // Capture "enter" key input + $(modal_name).on('keydown', 'input', function(event) { + if (event.keyCode == 13) { + event.preventDefault(); + // Simulate a click on the 'Submit' button + $(modal_name).find("#modal-form-submit").click(); + + return false; + } + }); + + $(modal_name).modal({ + backdrop: 'static', + keyboard: false, + }); + + // Set labels based on supplied options + modalSetTitle(modal_name, options.title || '{% trans "Form Title" %}'); + modalSetSubmitText(modal_name, options.submitText || '{% trans "Submit" %}'); + modalSetCloseText(modal_name, options.cancelText || '{% trans "Cancel" %}'); + + if (options.hideSubmitButton) { + $(modal_name).find('#modal-form-submit').hide(); + } + + if (options.hideCloseButton) { + $(modal_name).find('#modal-form-cancel').hide(); + } + + // Return the "name" of the modal + return modal_name; +} + + function makeOption(text, value, title) { /* Format an option for a select element */ @@ -444,25 +559,18 @@ function showAlertDialog(title, content, options={}) { * * title - Title text * content - HTML content of the dialog window - * options: - * modal - modal form to use (default = '#modal-alert-dialog') */ - var modal = options.modal || '#modal-alert-dialog'; - $(modal).on('shown.bs.modal', function() { - $(modal + ' .modal-form-content').scrollTop(0); + var modal = createNewModal({ + title: title, + cancelText: '{% trans "Close" %}', + hideSubmitButton: true, }); - modalSetTitle(modal, title); - modalSetContent(modal, content); + modalSetContent(modal, content); - $(modal).modal({ - backdrop: 'static', - keyboard: false, - }); - - $(modal).modal('show'); + $(modal).modal('show'); } @@ -479,22 +587,15 @@ function showQuestionDialog(title, content, options={}) { * cancel - Functino to run if the user presses 'Cancel' */ - var modal = options.modal || '#modal-question-dialog'; - - $(modal).on('shown.bs.modal', function() { - $(modal + ' .modal-form-content').scrollTop(0); + var modal = createNewModal({ + title: title, + submitText: options.accept_text || '{% trans "Accept" %}', + cancelText: options.cancel_text || '{% trans "Cancel" %}', }); - modalSetTitle(modal, title); modalSetContent(modal, content); - var accept_text = options.accept_text || '{% trans "Accept" %}'; - var cancel_text = options.cancel_text || '{% trans "Cancel" %}'; - - $(modal).find('#modal-form-cancel').html(cancel_text); - $(modal).find('#modal-form-accept').html(accept_text); - - $(modal).on('click', '#modal-form-accept', function() { + $(modal).on('click', "#modal-form-submit", function() { $(modal).modal('hide'); if (options.accept) { @@ -502,14 +603,6 @@ function showQuestionDialog(title, content, options={}) { } }); - $(modal).on('click', 'modal-form-cancel', function() { - $(modal).modal('hide'); - - if (options.cancel) { - options.cancel(); - } - }); - $(modal).modal('show'); } @@ -672,6 +765,9 @@ function attachSecondaryModal(modal, options) { function attachSecondaries(modal, secondaries) { /* Attach a provided list of secondary modals */ + // 2021-07-18 - Secondary modals will be disabled for now, until they are re-implemented in the "API forms" architecture + return; + for (var i = 0; i < secondaries.length; i++) { attachSecondaryModal(modal, secondaries[i]); } @@ -991,8 +1087,6 @@ function hideModalImage() { function showModalImage(image_url) { // Display full-screen modal image - console.log('showing modal image: ' + image_url); - var modal = $('#modal-image-dialog'); // Set image content diff --git a/InvenTree/templates/js/model_renderers.js b/InvenTree/templates/js/model_renderers.js new file mode 100644 index 0000000000..12e00cab2c --- /dev/null +++ b/InvenTree/templates/js/model_renderers.js @@ -0,0 +1,232 @@ +{% load i18n %} + + +function blankImage() { + return `/static/img/blank_image.png`; +} + +// Render a select2 thumbnail image +function select2Thumbnail(image) { + if (!image) { + image = blankImage(); + } + + return ``; +} + + +/* + * This file contains functions for rendering various InvenTree database models, + * in particular for displaying them in modal forms in a 'select2' context. + * + * Each renderer is provided with three arguments: + * + * - name: The 'name' of the model instance in the referring model + * - data: JSON data which represents the model instance. Returned via a GET request. + * - parameters: The field parameters provided via an OPTIONS request to the endpoint. + * - options: User options provided by the client + */ + + +// Renderer for "Company" model +function renderCompany(name, data, parameters, options) { + + var html = select2Thumbnail(data.image); + + html += `${data.name} - ${data.description}`; + + html += `{% trans "Company ID" %}: ${data.pk}`; + + return html; +} + + +// Renderer for "StockItem" model +function renderStockItem(name, data, parameters, options) { + + var image = data.part_detail.thumbnail || data.part_detail.image || blankImage(); + + var html = ``; + + html += ` ${data.part_detail.full_name || data.part_detail.name}`; + + if (data.serial && data.quantity == 1) { + html += ` - {% trans "Serial Number" %}: ${data.serial}`; + } else { + html += ` - {% trans "Quantity" %}: ${data.quantity}`; + } + + if (data.part_detail.description) { + html += `

                ${data.part_detail.description}

                `; + } + + return html; +} + + +// Renderer for "StockLocation" model +function renderStockLocation(name, data, parameters, options) { + + var level = '- '.repeat(data.level); + + var html = `${level}${data.pathstring}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + html += `{% trans "Location ID" %}: ${data.pk}`; + + return html; +} + + +function renderBuild(name, data, parameters, options) { + + var image = null; + + if (data.part_detail && data.part_detail.thumbnail) { + image = data.part_detail.thumbnail; + } + + var html = select2Thumbnail(image); + + html += `${data.reference} - ${data.quantity} x ${data.part_detail.full_name}`; + html += `{% trans "Build ID" %}: ${data.pk}`; + + html += `

                ${data.title}

                `; + + return html; +} + + +// Renderer for "Part" model +function renderPart(name, data, parameters, options) { + + var html = select2Thumbnail(data.image); + + html += ` ${data.full_name || data.name}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + html += `{% trans "Part ID" %}: ${data.pk}`; + + return html; +} + +// Renderer for "User" model +function renderUser(name, data, parameters, options) { + + var html = `${data.username}`; + + if (data.first_name && data.last_name) { + html += ` - ${data.first_name} ${data.last_name}`; + } + + return html; +} + + +// Renderer for "Owner" model +function renderOwner(name, data, parameters, options) { + + var html = `${data.name}`; + + switch (data.label) { + case 'user': + html += ``; + break; + case 'group': + html += ``; + break; + default: + break; + } + + return html; +} + + +// Renderer for "PartCategory" model +function renderPartCategory(name, data, parameters, options) { + + var level = '- '.repeat(data.level); + + var html = `${level}${data.pathstring}`; + + if (data.description) { + html += ` - ${data.description}`; + } + + html += `{% trans "Category ID" %}: ${data.pk}`; + + return html; +} + + +function renderPartParameterTemplate(name, data, parameters, options) { + + var html = `${data.name} - [${data.units}]`; + + return html; +} + + +// Renderer for "ManufacturerPart" model +function renderManufacturerPart(name, data, parameters, options) { + + var manufacturer_image = null; + var part_image = null; + + if (data.manufacturer_detail) { + manufacturer_image = data.manufacturer_detail.image; + } + + if (data.part_detail) { + part_image = data.part_detail.thumbnail || data.part_detail.image; + } + + var html = ''; + + html += select2Thumbnail(manufacturer_image); + html += select2Thumbnail(part_image); + + html += ` ${data.manufacturer_detail.name} - ${data.MPN}`; + html += ` - ${data.part_detail.full_name}`; + + html += `{% trans "Manufacturer Part ID" %}: ${data.pk}`; + + return html; +} + + +// Renderer for "SupplierPart" model +function renderSupplierPart(name, data, parameters, options) { + + var supplier_image = null; + var part_image = null; + + if (data.supplier_detail) { + supplier_image = data.supplier_detail.image; + } + + if (data.part_detail) { + part_image = data.part_detail.thumbnail || data.part_detail.image; + } + + var html = ''; + + html += select2Thumbnail(supplier_image); + html += select2Thumbnail(part_image); + + html += ` ${data.supplier_detail.name} - ${data.SKU}`; + html += ` - ${data.part_detail.full_name}`; + + html += `{% trans "Supplier Part ID" %}: ${data.pk}`; + + + return html; + +} diff --git a/InvenTree/templates/js/nav.js b/InvenTree/templates/js/nav.js new file mode 100644 index 0000000000..aff3435b21 --- /dev/null +++ b/InvenTree/templates/js/nav.js @@ -0,0 +1,84 @@ + +/* +* Attach callbacks to navigation bar elements. +* +* Searches for elements with the class 'nav-toggle'. +* A callback is added to each element, +* to display the matching panel. +* +* The 'id' of the .nav-toggle element should be of the form "select-", +* and point to a matching "panel-" +*/ +function attachNavCallbacks(options={}) { + + $('.nav-toggle').click(function() { + var el = $(this); + + // Find the matching "panel" element + var panelName = el.attr('id').replace('select-', ''); + + activatePanel(panelName, options); + }); + + var panelClass = options.name || 'unknown'; + + /* Look for a default panel to initialize + * First preference = URL parameter e.g. ?display=part-stock + * Second preference = localStorage + * Third preference = default + */ + var defaultPanel = $.urlParam('display') || localStorage.getItem(`inventree-selected-panel-${panelClass}`) || options.default; + + if (defaultPanel) { + activatePanel(defaultPanel); + } +} + + +function activatePanel(panelName, options={}) { + + var panelClass = options.name || 'unknown'; + + // First, cause any other panels to "fade out" + $('.panel-visible').hide(); + $('.panel-visible').removeClass('panel-visible'); + + // Find the target panel + var panel = `#panel-${panelName}`; + var select = `#select-${panelName}`; + + // Check that the selected panel (and select) exist + if ($(panel).length && $(select).length) { + // Yep, both are displayed + } else { + // Either the select or the panel are not displayed! + // Iterate through the available 'select' elements until one matches + panelName = null; + + $('.nav-toggle').each(function(item) { + var panel_name = $(this).attr('id').replace('select-', ''); + + if ($(`#panel-${panel_name}`).length && (panelName == null)) { + panelName = panel_name; + } + + panel = `#panel-${panelName}`; + select = `#select-${panelName}`; + }); + } + + // Save the selected panel + localStorage.setItem(`inventree-selected-panel-${panelClass}`, panelName); + + // Display the panel + $(panel).addClass('panel-visible'); + $(panel).fadeIn(100); + + // Un-select all selectors + $('.list-group-item').removeClass('active'); + + // Find the associated selector + var select = `#select-${panelName}`; + + $(select).parent('.list-group-item').addClass('active'); +} \ No newline at end of file diff --git a/InvenTree/templates/js/order.js b/InvenTree/templates/js/order.js index 649357b083..7091eb0577 100644 --- a/InvenTree/templates/js/order.js +++ b/InvenTree/templates/js/order.js @@ -1,6 +1,70 @@ {% load i18n %} {% load inventree_extras %} + +// Create a new SalesOrder +function createSalesOrder(options={}) { + + constructForm('{% url "api-so-list" %}', { + method: 'POST', + fields: { + reference: { + prefix: '{% settings_value "SALESORDER_REFERENCE_PREFIX" %}', + }, + customer: { + value: options.customer, + }, + customer_reference: {}, + description: {}, + target_date: { + icon: 'fa-calendar-alt', + }, + link: { + icon: 'fa-link', + }, + responsible: { + icon: 'fa-user', + } + }, + onSuccess: function(data) { + location.href = `/order/sales-order/${data.pk}/`; + }, + title: '{% trans "Create Sales Order" %}', + }); +} + +// Create a new PurchaseOrder +function createPurchaseOrder(options={}) { + + constructForm('{% url "api-po-list" %}', { + method: 'POST', + fields: { + reference: { + prefix: "{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}", + }, + supplier: { + value: options.supplier, + }, + supplier_reference: {}, + description: {}, + target_date: { + icon: 'fa-calendar-alt', + }, + link: { + icon: 'fa-link', + }, + responsible: { + icon: 'fa-user', + } + }, + onSuccess: function(data) { + location.href = `/order/purchase-order/${data.pk}/`; + }, + title: '{% trans "Create Purchase Order" %}', + }); +} + + function removeOrderRowFromOrderWizard(e) { /* Remove a part selection from an order form. */ @@ -266,6 +330,11 @@ function loadSalesOrderTable(table, options) { field: 'customer_detail', title: '{% trans "Customer" %}', formatter: function(value, row, index, field) { + + if (!row.customer_detail) { + return '{% trans "Invalid Customer" %}'; + } + return imageHoverIcon(row.customer_detail.image) + renderLink(row.customer_detail.name, `/company/${row.customer}/sales-orders/`); } }, @@ -391,6 +460,7 @@ function loadSalesOrderAllocationTable(table, options={}) { { field: 'quantity', title: '{% trans "Quantity" %}', + sortable: true, } ] }); diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 66174e2f15..169c722d79 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -13,6 +13,94 @@ function yesNoLabel(value) { } } + +function editPart(pk, options={}) { + + var url = `/api/part/${pk}/`; + + var fields = { + category: { + /* + secondary: { + label: '{% trans "New Category" %}', + title: '{% trans "Create New Part Category" %}', + api_url: '{% url "api-part-category-list" %}', + method: 'POST', + fields: { + name: {}, + description: {}, + parent: { + secondary: { + title: '{% trans "New Parent" %}', + api_url: '{% url "api-part-category-list" %}', + method: 'POST', + fields: { + name: {}, + description: {}, + parent: {}, + } + } + }, + } + }, + */ + }, + name: { + placeholder: 'part name', + }, + IPN: {}, + description: {}, + revision: {}, + keywords: { + icon: 'fa-key', + }, + variant_of: {}, + link: { + icon: 'fa-link', + }, + default_location: { + /* + secondary: { + label: '{% trans "New Location" %}', + title: '{% trans "Create new stock location" %}', + }, + */ + }, + default_supplier: { + filters: { + part: pk, + part_detail: true, + manufacturer_detail: true, + supplier_detail: true, + }, + /* + secondary: { + label: '{% trans "New Supplier Part" %}', + title: '{% trans "Create new supplier part" %}', + } + */ + }, + units: {}, + minimum_stock: {}, + virtual: {}, + is_template: {}, + assembly: {}, + component: {}, + trackable: {}, + purchaseable: {}, + salable: {}, + active: {}, + }; + + constructForm(url, { + fields: fields, + title: '{% trans "Edit Part" %}', + reload: true, + }); + +} + + function toggleStar(options) { /* Toggle the 'starred' status of a part. * Performs AJAX queries and updates the display on the button. @@ -220,6 +308,107 @@ function loadSimplePartTable(table, url, options={}) { } +function loadPartParameterTable(table, url, options) { + + var params = options.params || {}; + + // Load filters + var filters = loadTableFilters("part-parameters"); + + for (var key in params) { + filters[key] = params[key]; + } + + // setupFilterLsit("#part-parameters", $(table)); + + $(table).inventreeTable({ + url: url, + original: params, + queryParams: filters, + name: 'partparameters', + groupBy: false, + formatNoMatches: function() { return '{% trans "No parameters found" %}'; }, + columns: [ + { + checkbox: true, + switchable: false, + visible: true, + }, + { + field: 'name', + title: '{% trans "Name" %}', + switchable: false, + sortable: true, + formatter: function(value, row) { + return row.template_detail.name; + } + }, + { + field: 'data', + title: '{% trans "Value" %}', + switchable: false, + sortable: true, + }, + { + field: 'units', + title: '{% trans "Units" %}', + switchable: true, + sortable: true, + formatter: function(value, row) { + return row.template_detail.units; + } + }, + { + field: 'actions', + title: '', + switchable: false, + sortable: false, + formatter: function(value, row) { + var pk = row.pk; + + var html = `
                `; + + html += makeIconButton('fa-edit icon-blue', 'button-parameter-edit', pk, '{% trans "Edit parameter" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-parameter-delete', pk, '{% trans "Delete parameter" %}'); + + html += `
                `; + + return html; + } + } + ], + onPostBody: function() { + // Setup button callbacks + $(table).find('.button-parameter-edit').click(function() { + var pk = $(this).attr('pk'); + + constructForm(`/api/part/parameter/${pk}/`, { + fields: { + data: {}, + }, + title: '{% trans "Edit Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + + $(table).find('.button-parameter-delete').click(function() { + var pk = $(this).attr('pk'); + + constructForm(`/api/part/parameter/${pk}/`, { + method: 'DELETE', + title: '{% trans "Delete Parameter" %}', + onSuccess: function() { + $(table).bootstrapTable('refresh'); + } + }); + }); + } + }); +} + + function loadParametricPartTable(table, options={}) { /* Load parametric table for part parameters * @@ -525,7 +714,7 @@ function loadPartTable(table, url, options={}) { var html = ''; - html = `
                `; + html = `
                `; data.forEach(function(row, index) { @@ -769,6 +958,159 @@ function loadPartTestTemplateTable(table, options) { } +function loadPriceBreakTable(table, options) { + /* + * Load PriceBreak table. + */ + + var name = options.name || 'pricebreak'; + var human_name = options.human_name || 'price break'; + var linkedGraph = options.linkedGraph || null; + var chart = null; + + table.inventreeTable({ + name: name, + method: 'get', + formatNoMatches: function() { + return `{% trans "No ${human_name} information found" %}`; + }, + url: options.url, + onLoadSuccess: function(tableData) { + if (linkedGraph) { + // sort array + tableData = tableData.sort((a,b)=>a.quantity-b.quantity); + + // split up for graph definition + var graphLabels = Array.from(tableData, x => x.quantity); + var graphData = Array.from(tableData, x => parseFloat(x.price)); + + // destroy chart if exists + if (chart){ + chart.destroy(); + } + chart = loadLineChart(linkedGraph, + { + labels: graphLabels, + datasets: [ + { + label: '{% trans "Unit Price" %}', + data: graphData, + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + stepped: true, + fill: true, + },] + } + ); + } + }, + columns: [ + { + field: 'pk', + title: 'ID', + visible: false, + switchable: false, + }, + { + field: 'quantity', + title: '{% trans "Quantity" %}', + sortable: true, + }, + { + field: 'price', + title: '{% trans "Price" %}', + sortable: true, + formatter: function(value, row, index) { + var html = value; + + html += `
                ` + + html += makeIconButton('fa-edit icon-blue', `button-${name}-edit`, row.pk, `{% trans "Edit ${human_name}" %}`); + html += makeIconButton('fa-trash-alt icon-red', `button-${name}-delete`, row.pk, `{% trans "Delete ${human_name}" %}`); + + html += `
                `; + + return html; + } + }, + ] + }); +} + +function loadLineChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: {position: 'bottom'}, + } + } + }); +} + +function initPriceBreakSet(table, options) { + + var part_id = options.part_id; + var pb_human_name = options.pb_human_name; + var pb_url_slug = options.pb_url_slug; + var pb_url = options.pb_url; + var pb_new_btn = options.pb_new_btn; + var pb_new_url = options.pb_new_url; + + var linkedGraph = options.linkedGraph || null; + + loadPriceBreakTable( + table, + { + name: pb_url_slug, + human_name: pb_human_name, + url: pb_url, + linkedGraph: linkedGraph, + } + ); + + function reloadPriceBreakTable(){ + table.bootstrapTable("refresh"); + } + + pb_new_btn.click(function() { + launchModalForm(pb_new_url, + { + success: reloadPriceBreakTable, + data: { + part: part_id, + } + } + ); + }); + + table.on('click', `.button-${pb_url_slug}-delete`, function() { + var pk = $(this).attr('pk'); + + launchModalForm( + `/part/${pb_url_slug}/${pk}/delete/`, + { + success: reloadPriceBreakTable + } + ); + }); + + table.on('click', `.button-${pb_url_slug}-edit`, function() { + var pk = $(this).attr('pk'); + + launchModalForm( + `/part/${pb_url_slug}/${pk}/edit/`, + { + success: reloadPriceBreakTable + } + ); + }); +} + + function loadStockPricingChart(context, data) { return new Chart(context, { type: 'bar', @@ -824,3 +1166,36 @@ function loadBomChart(context, data) { } }); } + +function loadSellPricingChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: {legend: {position: 'bottom'}}, + scales: { + y: { + type: 'linear', + position: 'left', + grid: {display: false}, + title: { + display: true, + text: '{% trans "Unit Price" %}' + } + }, + y1: { + type: 'linear', + position: 'right', + grid: {display: false}, + titel: { + display: true, + text: '{% trans "Quantity" %}', + position: 'right' + } + }, + }, + } + }); +} diff --git a/InvenTree/templates/js/stock.js b/InvenTree/templates/js/stock.js index 06bbb7c20e..947e7fb3e9 100644 --- a/InvenTree/templates/js/stock.js +++ b/InvenTree/templates/js/stock.js @@ -20,6 +20,364 @@ function stockStatusCodes() { } +/* + * Export stock table + */ +function exportStock(params={}) { + + constructFormBody({}, { + title: '{% trans "Export Stock" %}', + fields: { + format: { + label: '{% trans "Format" %}', + help_text: '{% trans "Select file format" %}', + required: true, + type: 'choice', + value: 'csv', + choices: [ + { value: 'csv', display_name: 'CSV' }, + { value: 'tsv', display_name: 'TSV' }, + { value: 'xls', display_name: 'XLS' }, + { value: 'xlsx', display_name: 'XLSX' }, + ] + }, + sublocations: { + label: '{% trans "Include Sublocations" %}', + help_text: '{% trans "Include stock items in sublocations" %}', + type: 'boolean', + value: 'true', + } + }, + onSubmit: function(fields, form_options) { + + var format = getFormFieldValue('format', fields['format'], form_options); + var cascade = getFormFieldValue('sublocations', fields['sublocations'], form_options); + + // Hide the modal + $(form_options.modal).modal('hide'); + + var url = `{% url "stock-export" %}?format=${format}&cascade=${cascade}`; + + for (var key in params) { + url += `&${key}=${params[key]}`; + } + + console.log(url); + location.href = url; + } + }); +} + + +/** + * Perform stock adjustments + */ +function adjustStock(action, items, options={}) { + + var formTitle = 'Form Title Here'; + var actionTitle = null; + + // API url + var url = null; + + var specifyLocation = false; + var allowSerializedStock = false; + + switch (action) { + case 'move': + formTitle = '{% trans "Transfer Stock" %}'; + actionTitle = '{% trans "Move" %}'; + specifyLocation = true; + allowSerializedStock = true; + url = '{% url "api-stock-transfer" %}'; + break; + case 'count': + formTitle = '{% trans "Count Stock" %}'; + actionTitle = '{% trans "Count" %}'; + url = '{% url "api-stock-count" %}'; + break; + case 'take': + formTitle = '{% trans "Remove Stock" %}'; + actionTitle = '{% trans "Take" %}'; + url = '{% url "api-stock-remove" %}'; + break; + case 'add': + formTitle = '{% trans "Add Stock" %}'; + actionTitle = '{% trans "Add" %}'; + url = '{% url "api-stock-add" %}'; + break; + case 'delete': + formTitle = '{% trans "Delete Stock" %}'; + allowSerializedStock = true; + break; + default: + break; + } + + // Generate modal HTML content + var html = ` + + + + + + + + + + + + `; + + var itemCount = 0; + + for (var idx = 0; idx < items.length; idx++) { + + var item = items[idx]; + + if ((item.serial != null) && !allowSerializedStock) { + continue; + } + + var pk = item.pk; + + var readonly = (item.serial != null); + var minValue = null; + var maxValue = null; + var value = null; + + switch (action) { + case 'move': + minValue = 0; + maxValue = item.quantity; + value = item.quantity; + break; + case 'add': + minValue = 0; + value = 0; + break; + case 'take': + minValue = 0; + value = 0; + break; + case 'count': + minValue = 0; + value = item.quantity; + break; + default: + break; + } + + var image = item.part_detail.thumbnail || item.part_detail.image || blankImage(); + + var status = stockStatusDisplay(item.status, { + classes: 'float-right' + }); + + var quantity = item.quantity; + + var location = locationDetail(item, false); + + if (item.location_detail) { + location = item.location_detail.pathstring; + } + + if (item.serial != null) { + quantity = `#${item.serial}`; + } + + var actionInput = ''; + + if (actionTitle != null) { + actionInput = constructNumberInput( + item.pk, + { + value: value, + min_value: minValue, + max_value: maxValue, + read_only: readonly, + title: readonly ? '{% trans "Quantity cannot be adjusted for serialized stock" %}' : '{% trans "Specify stock quantity" %}', + } + ) + }; + + var buttons = `
                `; + + buttons += makeIconButton( + 'fa-times icon-red', + 'button-stock-item-remove', + pk, + '{% trans "Remove stock item" %}', + ); + + buttons += `
                `; + + html += ` + + + + + + + `; + + itemCount += 1; + } + + if (itemCount == 0) { + showAlertDialog( + '{% trans "Select Stock Items" %}', + '{% trans "You must select at least one available stock item" %}', + ); + + return; + } + + html += `
                {% trans "Part" %}{% trans "Stock" %}{% trans "Location" %}${actionTitle || ''}
                ${item.part_detail.full_name}${quantity}${status}${location} +
                + ${actionInput} +
                +
                +
                ${buttons}
                `; + + var modal = createNewModal({ + title: formTitle, + }); + + // Extra fields + var extraFields = { + location: { + label: '{% trans "Location" %}', + help_text: '{% trans "Select destination stock location" %}', + type: 'related field', + required: true, + api_url: `/api/stock/location/`, + model: 'stocklocation', + }, + notes: { + label: '{% trans "Notes" %}', + help_text: '{% trans "Stock transaction notes" %}', + type: 'string', + } + }; + + if (!specifyLocation) { + delete extraFields.location; + } + + constructFormBody({}, { + preFormContent: html, + fields: extraFields, + confirm: true, + confirmMessage: '{% trans "Confirm stock adjustment" %}', + modal: modal, + onSubmit: function(fields, opts) { + + // "Delete" action gets handled differently + if (action == 'delete') { + + var requests = []; + + items.forEach(function(item) { + requests.push( + inventreeDelete( + `/api/stock/${item.pk}/`, + ) + ) + }); + + // Wait for *all* the requests to complete + $.when.apply($, requests).then(function() { + // Destroy the modal window + $(modal).modal('hide'); + + if (options.onSuccess) { + options.onSuccess(); + } + }); + + return; + } + + // Data to transmit + var data = { + items: [], + }; + + // Add values for each selected stock item + items.forEach(function(item) { + + var q = getFormFieldValue(item.pk, {}, {modal: modal}); + + if (q != null) { + data.items.push({pk: item.pk, quantity: q}); + } + }); + + // Add in extra field data + for (field_name in extraFields) { + data[field_name] = getFormFieldValue( + field_name, + fields[field_name], + { + modal: modal, + } + ); + } + + inventreePut( + url, + data, + { + method: 'POST', + success: function(response, status) { + + // Destroy the modal window + $(modal).modal('hide'); + + if (options.onSuccess) { + options.onSuccess(); + } + }, + error: function(xhr) { + switch (xhr.status) { + case 400: + + // Handle errors for standard fields + handleFormErrors( + xhr.responseJSON, + extraFields, + { + modal: modal, + } + ) + + break; + default: + $(modal).modal('hide'); + showApiError(xhr); + break; + } + } + } + ); + } + }); + + // Attach callbacks for the action buttons + $(modal).find('.button-stock-item-remove').click(function() { + var pk = $(this).attr('pk'); + + $(modal).find(`#stock_item_${pk}`).remove(); + }); + + attachToggle(modal); + + $(modal + ' .select2-container').addClass('select-full-width'); + $(modal + ' .select2-container').css('width', '100%'); +} + + function removeStockRow(e) { // Remove a selected row from a stock modal form @@ -179,27 +537,32 @@ function loadStockTestResultsTable(table, options) { var match = false; var override = false; + // Extract the simplified test key var key = item.key; // Attempt to associate this result with an existing test - tableData.forEach(function(row, index) { + for (var idx = 0; idx < tableData.length; idx++) { + + var row = tableData[idx]; if (key == row.key) { item.test_name = row.test_name; item.required = row.required; - match = true; - if (row.result == null) { item.parent = parent_node; - tableData[index] = item; + tableData[idx] = item; override = true; } else { item.parent = row.pk; } + + match = true; + + break; } - }); + } // No match could be found if (!match) { @@ -223,6 +586,58 @@ function loadStockTestResultsTable(table, options) { } + +function locationDetail(row, showLink=true) { + /* + * Function to display a "location" of a StockItem. + * + * Complicating factors: A StockItem may not actually *be* in a location! + * - Could be at a customer + * - Could be installed in another stock item + * - Could be assigned to a sales order + * - Could be currently in production! + * + * So, instead of being naive, we'll check! + */ + + // Display text + var text = ''; + + // URL (optional) + var url = ''; + + if (row.is_building && row.build) { + // StockItem is currently being built! + text = '{% trans "In production" %}'; + url = `/build/${row.build}/`; + } else if (row.belongs_to) { + // StockItem is installed inside a different StockItem + text = `{% trans "Installed in Stock Item" %} ${row.belongs_to}`; + url = `/stock/item/${row.belongs_to}/installed/`; + } else if (row.customer) { + // StockItem has been assigned to a customer + text = '{% trans "Shipped to customer" %}'; + url = `/company/${row.customer}/assigned-stock/`; + } else if (row.sales_order) { + // StockItem has been assigned to a sales order + text = '{% trans "Assigned to Sales Order" %}'; + url = `/order/sales-order/${row.sales_order}/`; + } else if (row.location) { + text = row.location_detail.pathstring; + url = `/stock/location/${row.location}/`; + } else { + text = '{% trans "No stock location set" %}'; + url = ''; + } + + if (showLink && url) { + return renderLink(text, url); + } else { + return text; + } +} + + function loadStockTable(table, options) { /* Load data into a stock table with adjustable options. * Fetches data (via AJAX) and loads into a bootstrap table. @@ -266,56 +681,6 @@ function loadStockTable(table, options) { filters[key] = params[key]; } - function locationDetail(row) { - /* - * Function to display a "location" of a StockItem. - * - * Complicating factors: A StockItem may not actually *be* in a location! - * - Could be at a customer - * - Could be installed in another stock item - * - Could be assigned to a sales order - * - Could be currently in production! - * - * So, instead of being naive, we'll check! - */ - - // Display text - var text = ''; - - // URL (optional) - var url = ''; - - if (row.is_building && row.build) { - // StockItem is currently being built! - text = '{% trans "In production" %}'; - url = `/build/${row.build}/`; - } else if (row.belongs_to) { - // StockItem is installed inside a different StockItem - text = `{% trans "Installed in Stock Item" %} ${row.belongs_to}`; - url = `/stock/item/${row.belongs_to}/installed/`; - } else if (row.customer) { - // StockItem has been assigned to a customer - text = '{% trans "Shipped to customer" %}'; - url = `/company/${row.customer}/assigned-stock/`; - } else if (row.sales_order) { - // StockItem has been assigned to a sales order - text = '{% trans "Assigned to Sales Order" %}'; - url = `/order/sales-order/${row.sales_order}/`; - } else if (row.location) { - text = row.location_detail.pathstring; - url = `/stock/location/${row.location}/`; - } else { - text = '{% trans "No stock location set" %}'; - url = ''; - } - - if (url) { - return renderLink(text, url); - } else { - return text; - } - } - var grouping = true; if ('grouping' in options) { @@ -680,6 +1045,29 @@ function loadStockTable(table, options) { return renderLink(text, link); } }, + { + field: 'supplier_part', + title: '{% trans "Supplier Part" %}', + visible: params['supplier_part_detail'] || false, + switchable: params['supplier_part_detail'] || false, + formatter: function(value, row) { + if (!value) { + return '-'; + } + + var link = `/supplier-part/${row.supplier_part}/stock/`; + + var text = ''; + + if (row.supplier_part_detail) { + text = `${row.supplier_part_detail.SKU}`; + } else { + text = `{% trans "Supplier part not specified" %}`; + } + + return renderLink(text, link); + } + }, { field: 'purchase_price', title: '{% trans "Purchase Price" %}', @@ -713,39 +1101,15 @@ function loadStockTable(table, options) { ] ); + function stockAdjustment(action) { var items = $("#stock-table").bootstrapTable("getSelections"); - var stock = []; - - items.forEach(function(item) { - stock.push(item.pk); - }); - - // Buttons for launching secondary modals - var secondary = []; - - if (action == 'move') { - secondary.push({ - field: 'destination', - label: '{% trans "New Location" %}', - title: '{% trans "Create new location" %}', - url: "/stock/location/new/", - }); - } - - launchModalForm("/stock/adjust/", - { - data: { - action: action, - stock: stock, - }, - success: function() { - $("#stock-table").bootstrapTable('refresh'); - }, - secondary: secondary, + adjustStock(action, items, { + onSuccess: function() { + $('#stock-table').bootstrapTable('refresh'); } - ); + }); } // Automatically link button callbacks @@ -1180,7 +1544,7 @@ function loadStockTrackingTable(table, options) { } else { - return '{% trans "No user information" %}'; + return `{% trans "No user information" %}`; } } }); @@ -1301,27 +1665,6 @@ function createNewStockItem(options) { }, ]; - options.secondary = [ - { - field: 'part', - label: '{% trans "New Part" %}', - title: '{% trans "Create New Part" %}', - url: "{% url 'part-create' %}", - }, - { - field: 'supplier_part', - label: '{% trans "New Supplier Part" %}', - title: '{% trans "Create new Supplier Part" %}', - url: "{% url 'supplier-part-create' %}" - }, - { - field: 'location', - label: '{% trans "New Location" %}', - title: '{% trans "Create New Location" %}', - url: "{% url 'stock-location-create' %}", - }, - ]; - launchModalForm("{% url 'stock-item-create' %}", options); } diff --git a/InvenTree/templates/js/table_filters.js b/InvenTree/templates/js/table_filters.js index d02fa50d80..78632d6d56 100644 --- a/InvenTree/templates/js/table_filters.js +++ b/InvenTree/templates/js/table_filters.js @@ -42,6 +42,10 @@ function getAvailableTableFilters(tableKey) { type: 'bool', title: '{% trans "Trackable Part" %}' }, + sub_part_assembly: { + type: 'bool', + title: '{% trans "Assembled Part" %}', + }, validated: { type: 'bool', title: '{% trans "Validated" %}', @@ -205,7 +209,12 @@ function getAvailableTableFilters(tableKey) { batch: { title: '{% trans "Batch" %}', description: '{% trans "Batch code" %}', - } + }, + has_purchase_price: { + type: 'bool', + title: '{% trans "Has purchase price" %}', + description: '{% trans "Show stock items which have a purchase price set" %}', + }, }; } diff --git a/InvenTree/templates/js/tables.js b/InvenTree/templates/js/tables.js index 96eb3f8123..afe1fefbc9 100644 --- a/InvenTree/templates/js/tables.js +++ b/InvenTree/templates/js/tables.js @@ -1,5 +1,11 @@ {% load i18n %} + +function reloadtable(table) { + $(table).bootstrapTable('refresh'); +} + + function editButton(url, text='Edit') { return ""; } @@ -68,7 +74,7 @@ function isNumeric(n) { * Reload a table which has already been made into a bootstrap table. * New filters can be optionally provided, to change the query params. */ -function reloadTable(table, filters) { +function reloadTableFilters(table, filters) { // Simply perform a refresh if (filters == null) { @@ -94,16 +100,11 @@ function reloadTable(table, filters) { } options.queryParams = function(tableParams) { - - for (key in params) { - tableParams[key] = params[key]; - } - - return tableParams; - } + return convertQueryParameters(tableParams, params); + }; table.bootstrapTable('refreshOptions', options); - table.bootstrapTable('refresh'); + table.bootstrapTable('refresh', filters); } @@ -122,6 +123,55 @@ function visibleColumnString(columns) { } +/* + * Convert bootstrap-table style parameters to "InvenTree" style +*/ +function convertQueryParameters(params, filters) { + + // Override the way that we ask the server to sort results + // It seems bootstrap-table does not offer a "native" way to do this... + if ('sort' in params) { + var order = params['order']; + + var ordering = params['sort'] || null; + + if (ordering) { + + if (order == 'desc') { + ordering = `-${ordering}`; + } + + params['ordering'] = ordering; + } + + delete params['sort']; + delete params['order']; + + } + + for (var key in filters) { + params[key] = filters[key]; + } + + // Add "order" back in (if it was originally specified by InvenTree) + // Annoyingly, "order" shadows some field names in InvenTree... + if ('order' in filters) { + params['order'] = filters['order']; + } + + // Remove searchable[] array (generated by bootstrap-table) + if ('searchable' in params) { + delete params['searchable']; + } + + if ('sortable' in params) { + delete params['sortable']; + } + + return params; +} + + /* Wrapper function for bootstrapTable. * Sets some useful defaults, and manage persistent settings. */ @@ -147,39 +197,8 @@ $.fn.inventreeTable = function(options) { var filters = options.queryParams || options.filters || {}; options.queryParams = function(params) { - - // Override the way that we ask the server to sort results - // It seems bootstrap-table does not offer a "native" way to do this... - if ('sort' in params) { - var order = params['order']; - - var ordering = params['sort'] || null; - - if (ordering) { - - if (order == 'desc') { - ordering = `-${ordering}`; - } - - params['ordering'] = ordering; - } - - delete params['sort']; - delete params['order']; - - } - - for (var key in filters) { - params[key] = filters[key]; - } - - // Add "order" back in (if it was originally specified by InvenTree) - // Annoyingly, "order" shadows some field names in InvenTree... - if ('order' in filters) { - params['order'] = filters['order']; - } - return params; - } + return convertQueryParameters(params, filters); + }; options.rememberOrder = true; diff --git a/InvenTree/templates/modals.html b/InvenTree/templates/modals.html index e0cae3e580..11ddc40938 100644 --- a/InvenTree/templates/modals.html +++ b/InvenTree/templates/modals.html @@ -7,7 +7,7 @@
                -