From bdc62dfcc3c65a66e0eaa0238ad1c3b90dac29ff Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 4 Apr 2022 23:53:35 +0200 Subject: [PATCH 01/37] mark active sample code as a sample --- InvenTree/plugin/integration.py | 8 ++++++++ InvenTree/templates/InvenTree/settings/plugin.html | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/InvenTree/plugin/integration.py b/InvenTree/plugin/integration.py index de95adb8f8..7797134b14 100644 --- a/InvenTree/plugin/integration.py +++ b/InvenTree/plugin/integration.py @@ -94,6 +94,14 @@ class IntegrationPluginBase(MixinBase, plugin_base.InvenTreePluginBase): """ return getattr(self, 'is_package', False) + @property + def is_sample(self): + """ + Is this plugin part of the samples? + """ + path = str(self.package_path) + return path.startswith('plugin/samples/') + # region properties @property def slug(self): diff --git a/InvenTree/templates/InvenTree/settings/plugin.html b/InvenTree/templates/InvenTree/settings/plugin.html index 139ce0d41a..3ea8d9734c 100644 --- a/InvenTree/templates/InvenTree/settings/plugin.html +++ b/InvenTree/templates/InvenTree/settings/plugin.html @@ -76,6 +76,12 @@ {% endfor %} {% endif %} + {% if plugin.is_sample %} + + {% trans "code sample" %} + + {% endif %} + {% if plugin.website %} {% endif %} From 7c126ed712a1bc56bcde376a54118afb1618ad0e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 19 Apr 2022 21:19:25 +1000 Subject: [PATCH 02/37] Added x_forwarded_for middleware Used to extract remote client IP (when behind balancer / proxy / etc) --- InvenTree/InvenTree/settings.py | 1 + requirements.txt | 91 +++++++++++++++++---------------- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index c6810d51b6..cd7290ccee 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -282,6 +282,7 @@ INSTALLED_APPS = [ MIDDLEWARE = CONFIG.get('middleware', [ 'django.middleware.security.SecurityMiddleware', + 'x_forwarded_for.middleware.XForwardedForMiddleware', 'user_sessions.middleware.SessionMiddleware', # db user sessions 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', diff --git a/requirements.txt b/requirements.txt index 0b0f95d864..640eb497dd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,46 +1,47 @@ # Please keep this list sorted -Django==3.2.12 # Django package -bleach==4.1.0 # HTML santization -certifi # Certifi is (most likely) installed through one of the requirements above -coreapi==2.3.0 # API documentation -coverage==5.3 # Unit test coverage -coveralls==2.1.2 # Coveralls linking (for Travis) -cryptography==3.4.8 # Cryptography support -django-admin-shell==0.1.2 # Python shell for the admin interface -django-allauth==0.45.0 # SSO for external providers via OpenID -django-allauth-2fa==0.8 # MFA / 2FA -django-cleanup==5.1.0 # Manage deletion of old / unused uploaded files -django-cors-headers==3.2.0 # CORS headers extension for DRF -django-crispy-forms==1.11.2 # Form helpers -django-debug-toolbar==2.2 # Debug / profiling toolbar -django-error-report==0.2.0 # Error report viewer for the admin interface -django-filter==2.4.0 # Extended filtering options -django-formtools==2.3 # Form wizard tools -django-import-export==2.5.0 # Data import / export for admin interface -django-maintenance-mode==0.16.1 # Shut down application while reloading etc. -django-markdownify==0.8.0 # Markdown rendering -django-markdownx==3.0.1 # Markdown form fields -django-money==1.1 # Django app for currency management -django-mptt==0.11.0 # Modified Preorder Tree Traversal -django-redis>=5.0.0 -django-q==1.3.4 # Background task scheduling -django-sql-utils==0.5.0 # Advanced query annotation / aggregation -django-stdimage==5.1.1 # Advanced ImageField management -django-test-migrations==1.1.0 # Unit testing for database migrations -django-user-sessions==1.7.1 # user sessions in DB -django-weasyprint==1.0.1 # django weasyprint integration -djangorestframework==3.12.4 # DRF framework -flake8==3.8.3 # PEP checking -gunicorn>=20.1.0 # Gunicorn web server -importlib_metadata # Backport for importlib.metadata -inventree # Install the latest version of the InvenTree API python library -markdown==3.3.4 # Force particular version of markdown -pep8-naming==0.11.1 # PEP naming convention extension -pillow==9.0.1 # Image manipulation -py-moneyed==0.8.0 # Specific version requirement for py-moneyed -pygments==2.7.4 # Syntax highlighting -python-barcode[images]==0.13.1 # Barcode generator -qrcode[pil]==6.1 # QR code generator -rapidfuzz==0.7.6 # Fuzzy string matching -tablib[xls,xlsx,yaml] # Support for XLS and XLSX formats -weasyprint==52.5 # PDF generation library (Note: in the future need to update to 53) +Django==3.2.12 # Django package +bleach==4.1.0 # HTML santization +certifi # Certifi is (most likely) installed through one of the requirements above +coreapi==2.3.0 # API documentation +coverage==5.3 # Unit test coverage +coveralls==2.1.2 # Coveralls linking (for Travis) +cryptography==3.4.8 # Cryptography support +django-admin-shell==0.1.2 # Python shell for the admin interface +django-allauth==0.45.0 # SSO for external providers via OpenID +django-allauth-2fa==0.8 # MFA / 2FA +django-cleanup==5.1.0 # Manage deletion of old / unused uploaded files +django-cors-headers==3.2.0 # CORS headers extension for DRF +django-crispy-forms==1.11.2 # Form helpers +django-debug-toolbar==2.2 # Debug / profiling toolbar +django-error-report==0.2.0 # Error report viewer for the admin interface +django-filter==2.4.0 # Extended filtering options +django-formtools==2.3 # Form wizard tools +django-import-export==2.5.0 # Data import / export for admin interface +django-maintenance-mode==0.16.1 # Shut down application while reloading etc. +django-markdownify==0.8.0 # Markdown rendering +django-markdownx==3.0.1 # Markdown form fields +django-money==1.1 # Django app for currency management +django-mptt==0.11.0 # Modified Preorder Tree Traversal +django-redis>=5.0.0 # Redis integration +django-q==1.3.4 # Background task scheduling +django-sql-utils==0.5.0 # Advanced query annotation / aggregation +django-stdimage==5.1.1 # Advanced ImageField management +django-test-migrations==1.1.0 # Unit testing for database migrations +django-user-sessions==1.7.1 # user sessions in DB +django-weasyprint==1.0.1 # django weasyprint integration +djangorestframework==3.12.4 # DRF framework +django-xforwardedfor-middleware==2.0 # IP forwarding metadata +flake8==3.8.3 # PEP checking +gunicorn>=20.1.0 # Gunicorn web server +importlib_metadata # Backport for importlib.metadata +inventree # Install the latest version of the InvenTree API python library +markdown==3.3.4 # Force particular version of markdown +pep8-naming==0.11.1 # PEP naming convention extension +pillow==9.0.1 # Image manipulation +py-moneyed==0.8.0 # Specific version requirement for py-moneyed +pygments==2.7.4 # Syntax highlighting +python-barcode[images]==0.13.1 # Barcode generator +qrcode[pil]==6.1 # QR code generator +rapidfuzz==0.7.6 # Fuzzy string matching +tablib[xls,xlsx,yaml] # Support for XLS and XLSX formats +weasyprint==52.5 # PDF generation library (Note: in the future need to update to 53) From 85c8b94d80e41f9dd16a232e9c80107a1a3375d0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 19 Apr 2022 22:09:30 +1000 Subject: [PATCH 03/37] Update nginx conf files --- docker/docker-compose.dev.yml | 6 +++--- docker/nginx.conf | 23 ++++++++++++++--------- docker/nginx.dev.conf | 24 +++++++++++++++--------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index ca0f837142..8cbe2a9e4d 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -7,9 +7,9 @@ version: "3.8" # - Serves media and static content directly from Django webserver # IMPORANT NOTE: -# The InvenTree docker image does not clone source code from git. -# Instead, you must specify *where* the source code is located, -# (on your local machine). +# The InvenTree development image does not clone source code from git. +# Instead, you must specify *where* the source code is located, (on your local machine). +# The default setup in this file should work straight out of the box, without modification # The django server will auto-detect any code changes and reload the server. services: diff --git a/docker/nginx.conf b/docker/nginx.conf index 271f65a89d..a412d4094a 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -4,24 +4,29 @@ server { # Listen for connection on (internal) port 80 listen 80; - location / { - # Change 'inventree-server' to the name of the inventree server container, - # and '8000' to the INVENTREE_WEB_PORT (if not default) - proxy_pass http://inventree-server:8000; + real_ip_header proxy_protocol; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; + location / { + + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-By $server_addr:$server_port; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header CLIENT_IP $remote_addr; + + proxy_pass_request_headers on; proxy_redirect off; client_max_body_size 100M; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; proxy_request_buffering off; + # Change 'inventree-server' to the name of the inventree server container, + # and '8000' to the INVENTREE_WEB_PORT (if not default) + proxy_pass http://inventree-server:8000; } # Redirect any requests for static files diff --git a/docker/nginx.dev.conf b/docker/nginx.dev.conf index 8fc47e622c..f3085ef57b 100644 --- a/docker/nginx.dev.conf +++ b/docker/nginx.dev.conf @@ -4,24 +4,30 @@ server { # Listen for connection on (internal) port 80 listen 80; - location / { - # Change 'inventree-dev-server' to the name of the inventree server container, - # and '8000' to the INVENTREE_WEB_PORT (if not default) - proxy_pass http://inventree-dev-server:8000; + real_ip_header proxy_protocol; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; + location / { + + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-By $server_addr:$server_port; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header CLIENT_IP $remote_addr; + + proxy_pass_request_headers on; proxy_redirect off; client_max_body_size 100M; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_buffering off; proxy_request_buffering off; + # Change 'inventree-dev-server' to the name of the inventree server container, + # and '8000' to the INVENTREE_WEB_PORT (if not default) + proxy_pass http://inventree-dev-server:8000; + } # Redirect any requests for static files From d93cc78bf6e7aa9b2274520c920ef570472d64ce Mon Sep 17 00:00:00 2001 From: Awf Wiswasi <55606355+awiswasi@users.noreply.github.com> Date: Tue, 19 Apr 2022 05:50:17 -0700 Subject: [PATCH 04/37] Fixed vulnerability to Cross-site Scripting (XSS) when accepting the value of altField option of the Datepicker widget from untrusted sources, which may lead to execution of untrusted code. Vulnerability fixed in jquery-ui@1.13.0 --- InvenTree/InvenTree/static/script/jquery-ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/jquery-ui/package.json b/InvenTree/InvenTree/static/script/jquery-ui/package.json index e3c846e3a8..dc32b2db84 100644 --- a/InvenTree/InvenTree/static/script/jquery-ui/package.json +++ b/InvenTree/InvenTree/static/script/jquery-ui/package.json @@ -2,7 +2,7 @@ "name": "jquery-ui", "title": "jQuery UI", "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", - "version": "1.12.1", + "version": "1.13.0", "homepage": "http://jqueryui.com", "author": { "name": "jQuery Foundation and other contributors", From 761e822a4e890e796e7517d0a84bb24254163f42 Mon Sep 17 00:00:00 2001 From: Awf Wiswasi <55606355+awiswasi@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:36:34 -0700 Subject: [PATCH 05/37] Updated jquery v1.12.1 to v1.13.0 to fix a possible XSS vulnerability. --- .../static/script/jquery-ui/jquery-ui.js | 30 +++++++++---------- .../static/script/jquery-ui/jquery-ui.min.js | 4 +-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.js b/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.js index aa871b2a59..bfed42f715 100644 --- a/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.js +++ b/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.js @@ -1,4 +1,4 @@ -/*! jQuery UI - v1.12.1 - 2021-07-18 +/*! jQuery UI - v1.13.0 - 2021-10-07 * http://jqueryui.com * Includes: widget.js, position.js, disable-selection.js, keycode.js, unique-id.js, widgets/resizable.js, widgets/autocomplete.js, widgets/menu.js, widgets/mouse.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ @@ -17,11 +17,11 @@ $.ui = $.ui || {}; -var version = $.ui.version = "1.12.1"; +var version = $.ui.version = "1.13.1"; /*! - * jQuery UI Widget 1.12.1 + * jQuery UI Widget 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -744,7 +744,7 @@ var widget = $.widget; /*! - * jQuery UI Position 1.12.1 + * jQuery UI Position 1.13.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1232,7 +1232,7 @@ var position = $.ui.position; /*! - * jQuery UI Disable Selection 1.12.1 + * jQuery UI Disable Selection 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1268,7 +1268,7 @@ var disableSelection = $.fn.extend( { /*! - * jQuery UI Keycode 1.12.1 + * jQuery UI Keycode 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1303,7 +1303,7 @@ var keycode = $.ui.keyCode = { /*! - * jQuery UI Unique ID 1.12.1 + * jQuery UI Unique ID 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1347,7 +1347,7 @@ var uniqueId = $.fn.extend( { var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); /*! - * jQuery UI Mouse 1.12.1 + * jQuery UI Mouse 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1368,7 +1368,7 @@ $( document ).on( "mouseup", function() { } ); var widgetsMouse = $.widget( "ui.mouse", { - version: "1.12.1", + version: "1.13.0", options: { cancel: "input, textarea, button, select, option", distance: 1, @@ -1592,7 +1592,7 @@ var plugin = $.ui.plugin = { /*! - * jQuery UI Resizable 1.12.1 + * jQuery UI Resizable 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -1612,7 +1612,7 @@ var plugin = $.ui.plugin = { $.widget( "ui.resizable", $.ui.mouse, { - version: "1.12.1", + version: "1.13.0", widgetEventPrefix: "resize", options: { alsoResize: false, @@ -2806,7 +2806,7 @@ var safeActiveElement = $.ui.safeActiveElement = function( document ) { /*! - * jQuery UI Menu 1.12.1 + * jQuery UI Menu 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -2826,7 +2826,7 @@ var safeActiveElement = $.ui.safeActiveElement = function( document ) { var widgetsMenu = $.widget( "ui.menu", { - version: "1.12.1", + version: "1.13.0", defaultElement: "
    ", delay: 300, options: { @@ -3461,7 +3461,7 @@ var widgetsMenu = $.widget( "ui.menu", { /*! - * jQuery UI Autocomplete 1.12.1 + * jQuery UI Autocomplete 1.13.0 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -3481,7 +3481,7 @@ var widgetsMenu = $.widget( "ui.menu", { $.widget( "ui.autocomplete", { - version: "1.12.1", + version: "1.13.0", defaultElement: "", options: { appendTo: null, diff --git a/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.min.js b/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.min.js index 9a48ddd9bd..d588421b84 100644 --- a/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.min.js +++ b/InvenTree/InvenTree/static/script/jquery-ui/jquery-ui.min.js @@ -1,6 +1,6 @@ -/*! jQuery UI - v1.12.1 - 2021-07-18 +/*! jQuery UI - v1.13.0 - 2021-10-07 * http://jqueryui.com * Includes: widget.js, position.js, disable-selection.js, keycode.js, unique-id.js, widgets/resizable.js, widgets/autocomplete.js, widgets/menu.js, widgets/mouse.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ -!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(z){z.ui=z.ui||{};z.ui.version="1.12.1";var n,i=0,a=Array.prototype.slice;z.cleanData=(n=z.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)try{(e=z._data(i,"events"))&&e.remove&&z(i).triggerHandler("remove")}catch(t){}n(t)}),z.widget=function(t,i,e){var s,n,o,h={},a=t.split(".")[0],l=a+"-"+(t=t.split(".")[1]);return e||(e=i,i=z.Widget),z.isArray(e)&&(e=z.extend.apply(null,[{}].concat(e))),z.expr[":"][l.toLowerCase()]=function(t){return!!z.data(t,l)},z[a]=z[a]||{},s=z[a][t],n=z[a][t]=function(t,e){if(!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},z.extend(n,s,{version:e.version,_proto:z.extend({},e),_childConstructors:[]}),(o=new i).options=z.widget.extend({},o.options),z.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}z.isFunction(s)?h[e]=function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:h[e]=s}),n.prototype=z.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},h,{constructor:n,namespace:a,widgetName:t,widgetFullName:l}),s?(z.each(s._childConstructors,function(t,e){var i=e.prototype;z.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),z.widget.bridge(t,n),n},z.widget.extend=function(t){for(var e,i,s=a.call(arguments,1),n=0,o=s.length;n",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=z(e||this.defaultElement||this)[0],this.element=z(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=z(),this.hoverable=z(),this.focusable=z(),this.classesElementLookup={},e!==this&&(z.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=z(e.style?e.ownerDocument:e.document||e),this.window=z(this.document[0].defaultView||this.document[0].parentWindow)),this.options=z.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:z.noop,_create:z.noop,_init:z.noop,destroy:function(){var i=this;this._destroy(),z.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:z.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return z.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=z.widget.extend({},this.options[t]),n=0;n
    "),i=e.children()[0];return z("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(E(s),E(n))?o.important="horizontal":o.important="vertical",c.using.call(this,t,o)}),h.offset(z.extend(r,{using:t}))})},z.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),z.ui.plugin={add:function(t,e,i){var s,n=z.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&z(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();function t(t){z(t).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){this._super(t,e),"handles"===t&&(this._removeHandles(),this._setupHandles())},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(z(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=z(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split(","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.append(n);this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=z(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=z(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add(this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=z(this.handles[e])[0])!==t.target&&!z.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=z(s.containment).scrollLeft()||0,i+=z(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=z(".ui-resizable-"+this.axis).css("cursor"),z("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),z.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(z.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),z("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,l=this.originalPosition.top+this.originalSize.height,r=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&r&&(t.left=a-e.minWidth),s&&r&&(t.left=a-e.maxWidth),h&&i&&(t.top=l-e.minHeight),n&&i&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return z.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e,i){return z.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return z.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return z.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){z.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),z.ui.plugin.add("resizable","animate",{stop:function(e){var i=z(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(z.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&z(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),z.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=z(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof z?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=z(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:z(document),left:0,top:0,width:z(document).width(),height:z(document).height()||document.body.parentNode.scrollHeight}):(i=z(h),s=[],z(["Top","Right","Left","Bottom"]).each(function(t,e){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=z(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0),i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=z(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=z(t.helper),h=o.offset(),a=o.outerWidth()-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&z(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&z(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),z.ui.plugin.add("resizable","alsoResize",{start:function(){var t=z(this).resizable("instance").options;z(t.alsoResize).each(function(){var t=z(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=z(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};z(s.alsoResize).each(function(){var t=z(this),s=z(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];z.each(e,function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){z(this).removeData("ui-resizable-alsoresize")}}),z.ui.plugin.add("resizable","ghost",{start:function(){var t=z(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==z.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=z(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=z(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),z.ui.plugin.add("resizable","grid",{resize:function(){var t,e=z(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,l=a[0]||1,r=a[1]||1,u=Math.round((s.width-n.width)/l)*l,c=Math.round((s.height-n.height)/r)*r,d=n.width+u,p=n.height+c,m=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>p;i.grid=a,g&&(d+=l),s&&(p+=r),m&&(d-=l),f&&(p-=r),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=p,e.position.top=o.top-c):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=p,e.position.left=o.left-u):((p-r<=0||d-l<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(t){var e=z(t.target),i=z(z.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&e.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),e.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&i.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var e,i;this.previousFilter||(e=z(t.target).closest(".ui-menu-item"),i=z(t.currentTarget),e[0]===i[0]&&(this._removeClass(i.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(t,i)))},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(t){this._delay(function(){z.contains(this.element[0],z.ui.safeActiveElement(this.document[0]))||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var t=this.element.find(".ui-menu-item").removeAttr("role aria-disabled").children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),t.children().each(function(){var t=z(this);t.data("ui-menu-submenu-caret")&&t.remove()})},_keydown:function(t){var e,i,s,n=!0;switch(t.keyCode){case z.ui.keyCode.PAGE_UP:this.previousPage(t);break;case z.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case z.ui.keyCode.HOME:this._move("first","first",t);break;case z.ui.keyCode.END:this._move("last","last",t);break;case z.ui.keyCode.UP:this.previous(t);break;case z.ui.keyCode.DOWN:this.next(t);break;case z.ui.keyCode.LEFT:this.collapse(t);break;case z.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case z.ui.keyCode.ENTER:case z.ui.keyCode.SPACE:this._activate(t);break;case z.ui.keyCode.ESCAPE:this.collapse(t);break;default:n=!1,e=this.previousFilter||"",s=!1,i=96<=t.keyCode&&t.keyCode<=105?(t.keyCode-96).toString():String.fromCharCode(t.keyCode),clearTimeout(this.filterTimer),i===e?s=!0:i=e+i,e=this._filterMenuItems(i),(e=s&&-1!==e.index(this.active.next())?this.active.nextAll(".ui-menu-item"):e).length||(i=String.fromCharCode(t.keyCode),e=this._filterMenuItems(i)),e.length?(this.focus(t,e),this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}n&&t.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var t,e,s=this,n=this.options.icons.submenu,i=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),e=i.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=z(this),e=t.prev(),i=z("").data("ui-menu-submenu-caret",!0);s._addClass(i,"ui-menu-icon","ui-icon "+n),e.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",e.attr("id"))}),this._addClass(e,"ui-menu","ui-widget ui-widget-content ui-front"),(t=i.add(this.element).find(this.options.items)).not(".ui-menu-item").each(function(){var t=z(this);s._isDivider(t)&&s._addClass(t,"ui-menu-divider","ui-widget-content")}),i=(e=t.not(".ui-menu-item, .ui-menu-divider")).children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(e,"ui-menu-item")._addClass(i,"ui-menu-item-wrapper"),t.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!z.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){var i;"icons"===t&&(i=this.element.find(".ui-menu-icon"),this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",String(t)),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),i=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),(i=e.children(".ui-menu")).length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(t){var e,i,s;this._hasScroll()&&(i=parseFloat(z.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(z.css(this.activeMenu[0],"paddingTop"))||0,e=t.offset().top-this.activeMenu.offset().top-i-s,i=this.activeMenu.scrollTop(),s=this.activeMenu.height(),t=t.outerHeight(),e<0?this.activeMenu.scrollTop(i+e):s",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var i,s,n,t=this.element[0].nodeName.toLowerCase(),e="textarea"===t,t="input"===t;this.isMultiLine=e||!t&&this._isContentEditable(this.element),this.valueMethod=this.element[e||t?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(t){if(this.element.prop("readOnly"))s=n=i=!0;else{s=n=i=!1;var e=z.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:i=!0,this._move("previousPage",t);break;case e.PAGE_DOWN:i=!0,this._move("nextPage",t);break;case e.UP:i=!0,this._keyEvent("previous",t);break;case e.DOWN:i=!0,this._keyEvent("next",t);break;case e.ENTER:this.menu.active&&(i=!0,t.preventDefault(),this.menu.select(t));break;case e.TAB:this.menu.active&&this.menu.select(t);break;case e.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(t),t.preventDefault());break;default:s=!0,this._searchTimeout(t)}}},keypress:function(t){if(i)return i=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||t.preventDefault());if(!s){var e=z.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:this._move("previousPage",t);break;case e.PAGE_DOWN:this._move("nextPage",t);break;case e.UP:this._keyEvent("previous",t);break;case e.DOWN:this._keyEvent("next",t)}}},input:function(t){if(n)return n=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){this.cancelBlur?delete this.cancelBlur:(clearTimeout(this.searching),this.close(t),this._change(t))}}),this._initSource(),this.menu=z("
      ").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,this.element[0]!==z.ui.safeActiveElement(this.document[0])&&this.element.trigger("focus")})},menufocus:function(t,e){var i;if(this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type)))return this.menu.blur(),void this.document.one("mousemove",function(){z(t.target).trigger(t.originalEvent)});i=e.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:i})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(i.value),(i=e.item.attr("aria-label")||i.value)&&z.trim(i).length&&(this.liveRegion.children().hide(),z("
      ").text(i).appendTo(this.liveRegion))},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==z.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=z("
      ",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(t){var e=this.menu.element[0];return t.target===this.element[0]||t.target===e||z.contains(e,t.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var t=this.options.appendTo;return(t=t&&(t.jquery||t.nodeType?z(t):this.document.find(t).eq(0)))&&t[0]||(t=this.element.closest(".ui-front, dialog")),t.length||(t=this.document[0].body),t},_initSource:function(){var i,s,n=this;z.isArray(this.options.source)?(i=this.options.source,this.source=function(t,e){e(z.ui.autocomplete.filter(i,t.term))}):"string"==typeof this.options.source?(s=this.options.source,this.source=function(t,e){n.xhr&&n.xhr.abort(),n.xhr=z.ajax({url:s,data:t,dataType:"json",success:function(t){e(t)},error:function(){e([])}})}):this.source=this.options.source},_searchTimeout:function(s){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),e=this.menu.element.is(":visible"),i=s.altKey||s.ctrlKey||s.metaKey||s.shiftKey;t&&(!t||e||i)||(this.selectedItem=null,this.search(null,s))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length").append(z("
      ").text(e.label)).appendTo(t)},_move:function(t,e){if(this.menu.element.is(":visible"))return this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),void this.menu.blur()):void this.menu[t](e);this.search(null,e)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){this.isMultiLine&&!this.menu.element.is(":visible")||(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),z.extend(z.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,e){var i=new RegExp(z.ui.autocomplete.escapeRegex(e),"i");return z.grep(t,function(t){return i.test(t.label||t.value||t)})}}),z.widget("ui.autocomplete",z.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(1").text(e).appendTo(this.liveRegion))}});z.ui.autocomplete}); \ No newline at end of file +!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(z){z.ui=z.ui||{};z.ui.version="1.13.0";var n,i=0,a=Array.prototype.slice;z.cleanData=(n=z.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)try{(e=z._data(i,"events"))&&e.remove&&z(i).triggerHandler("remove")}catch(t){}n(t)}),z.widget=function(t,i,e){var s,n,o,h={},a=t.split(".")[0],l=a+"-"+(t=t.split(".")[1]);return e||(e=i,i=z.Widget),z.isArray(e)&&(e=z.extend.apply(null,[{}].concat(e))),z.expr[":"][l.toLowerCase()]=function(t){return!!z.data(t,l)},z[a]=z[a]||{},s=z[a][t],n=z[a][t]=function(t,e){if(!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},z.extend(n,s,{version:e.version,_proto:z.extend({},e),_childConstructors:[]}),(o=new i).options=z.widget.extend({},o.options),z.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}z.isFunction(s)?h[e]=function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:h[e]=s}),n.prototype=z.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},h,{constructor:n,namespace:a,widgetName:t,widgetFullName:l}),s?(z.each(s._childConstructors,function(t,e){var i=e.prototype;z.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),z.widget.bridge(t,n),n},z.widget.extend=function(t){for(var e,i,s=a.call(arguments,1),n=0,o=s.length;n",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=z(e||this.defaultElement||this)[0],this.element=z(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=z(),this.hoverable=z(),this.focusable=z(),this.classesElementLookup={},e!==this&&(z.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=z(e.style?e.ownerDocument:e.document||e),this.window=z(this.document[0].defaultView||this.document[0].parentWindow)),this.options=z.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:z.noop,_create:z.noop,_init:z.noop,destroy:function(){var i=this;this._destroy(),z.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:z.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return z.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=z.widget.extend({},this.options[t]),n=0;n
      "),i=e.children()[0];return z("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(E(s),E(n))?o.important="horizontal":o.important="vertical",c.using.call(this,t,o)}),h.offset(z.extend(r,{using:t}))})},z.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),z.ui.plugin={add:function(t,e,i){var s,n=z.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n
      ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&z(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();function t(t){z(t).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){this._super(t,e),"handles"===t&&(this._removeHandles(),this._setupHandles())},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(z(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=z(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split(","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.append(n);this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=z(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=z(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add(this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=z(this.handles[e])[0])!==t.target&&!z.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=z(s.containment).scrollLeft()||0,i+=z(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=z(".ui-resizable-"+this.axis).css("cursor"),z("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),z.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(z.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),z("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,l=this.originalPosition.top+this.originalSize.height,r=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&r&&(t.left=a-e.minWidth),s&&r&&(t.left=a-e.maxWidth),h&&i&&(t.top=l-e.minHeight),n&&i&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e
      "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return z.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e,i){return z.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return z.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return z.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){z.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),z.ui.plugin.add("resizable","animate",{stop:function(e){var i=z(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(z.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&z(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),z.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=z(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof z?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=z(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:z(document),left:0,top:0,width:z(document).width(),height:z(document).height()||document.body.parentNode.scrollHeight}):(i=z(h),s=[],z(["Top","Right","Left","Bottom"]).each(function(t,e){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=z(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0),i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=z(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=z(t.helper),h=o.offset(),a=o.outerWidth()-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&z(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&z(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),z.ui.plugin.add("resizable","alsoResize",{start:function(){var t=z(this).resizable("instance").options;z(t.alsoResize).each(function(){var t=z(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=z(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};z(s.alsoResize).each(function(){var t=z(this),s=z(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];z.each(e,function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){z(this).removeData("ui-resizable-alsoresize")}}),z.ui.plugin.add("resizable","ghost",{start:function(){var t=z(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==z.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=z(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=z(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),z.ui.plugin.add("resizable","grid",{resize:function(){var t,e=z(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,l=a[0]||1,r=a[1]||1,u=Math.round((s.width-n.width)/l)*l,c=Math.round((s.height-n.height)/r)*r,d=n.width+u,p=n.height+c,m=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>p;i.grid=a,g&&(d+=l),s&&(p+=r),m&&(d-=l),f&&(p-=r),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=p,e.position.top=o.top-c):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=p,e.position.left=o.left-u):((p-r<=0||d-l<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(t){var e=z(t.target),i=z(z.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&e.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),e.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&i.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var e,i;this.previousFilter||(e=z(t.target).closest(".ui-menu-item"),i=z(t.currentTarget),e[0]===i[0]&&(this._removeClass(i.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(t,i)))},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(t){this._delay(function(){z.contains(this.element[0],z.ui.safeActiveElement(this.document[0]))||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var t=this.element.find(".ui-menu-item").removeAttr("role aria-disabled").children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),t.children().each(function(){var t=z(this);t.data("ui-menu-submenu-caret")&&t.remove()})},_keydown:function(t){var e,i,s,n=!0;switch(t.keyCode){case z.ui.keyCode.PAGE_UP:this.previousPage(t);break;case z.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case z.ui.keyCode.HOME:this._move("first","first",t);break;case z.ui.keyCode.END:this._move("last","last",t);break;case z.ui.keyCode.UP:this.previous(t);break;case z.ui.keyCode.DOWN:this.next(t);break;case z.ui.keyCode.LEFT:this.collapse(t);break;case z.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case z.ui.keyCode.ENTER:case z.ui.keyCode.SPACE:this._activate(t);break;case z.ui.keyCode.ESCAPE:this.collapse(t);break;default:n=!1,e=this.previousFilter||"",s=!1,i=96<=t.keyCode&&t.keyCode<=105?(t.keyCode-96).toString():String.fromCharCode(t.keyCode),clearTimeout(this.filterTimer),i===e?s=!0:i=e+i,e=this._filterMenuItems(i),(e=s&&-1!==e.index(this.active.next())?this.active.nextAll(".ui-menu-item"):e).length||(i=String.fromCharCode(t.keyCode),e=this._filterMenuItems(i)),e.length?(this.focus(t,e),this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}n&&t.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var t,e,s=this,n=this.options.icons.submenu,i=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),e=i.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=z(this),e=t.prev(),i=z("").data("ui-menu-submenu-caret",!0);s._addClass(i,"ui-menu-icon","ui-icon "+n),e.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",e.attr("id"))}),this._addClass(e,"ui-menu","ui-widget ui-widget-content ui-front"),(t=i.add(this.element).find(this.options.items)).not(".ui-menu-item").each(function(){var t=z(this);s._isDivider(t)&&s._addClass(t,"ui-menu-divider","ui-widget-content")}),i=(e=t.not(".ui-menu-item, .ui-menu-divider")).children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(e,"ui-menu-item")._addClass(i,"ui-menu-item-wrapper"),t.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!z.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){var i;"icons"===t&&(i=this.element.find(".ui-menu-icon"),this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",String(t)),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),i=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),(i=e.children(".ui-menu")).length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(t){var e,i,s;this._hasScroll()&&(i=parseFloat(z.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(z.css(this.activeMenu[0],"paddingTop"))||0,e=t.offset().top-this.activeMenu.offset().top-i-s,i=this.activeMenu.scrollTop(),s=this.activeMenu.height(),t=t.outerHeight(),e<0?this.activeMenu.scrollTop(i+e):s",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var i,s,n,t=this.element[0].nodeName.toLowerCase(),e="textarea"===t,t="input"===t;this.isMultiLine=e||!t&&this._isContentEditable(this.element),this.valueMethod=this.element[e||t?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(t){if(this.element.prop("readOnly"))s=n=i=!0;else{s=n=i=!1;var e=z.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:i=!0,this._move("previousPage",t);break;case e.PAGE_DOWN:i=!0,this._move("nextPage",t);break;case e.UP:i=!0,this._keyEvent("previous",t);break;case e.DOWN:i=!0,this._keyEvent("next",t);break;case e.ENTER:this.menu.active&&(i=!0,t.preventDefault(),this.menu.select(t));break;case e.TAB:this.menu.active&&this.menu.select(t);break;case e.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(t),t.preventDefault());break;default:s=!0,this._searchTimeout(t)}}},keypress:function(t){if(i)return i=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||t.preventDefault());if(!s){var e=z.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:this._move("previousPage",t);break;case e.PAGE_DOWN:this._move("nextPage",t);break;case e.UP:this._keyEvent("previous",t);break;case e.DOWN:this._keyEvent("next",t)}}},input:function(t){if(n)return n=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){this.cancelBlur?delete this.cancelBlur:(clearTimeout(this.searching),this.close(t),this._change(t))}}),this._initSource(),this.menu=z("
        ").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,this.element[0]!==z.ui.safeActiveElement(this.document[0])&&this.element.trigger("focus")})},menufocus:function(t,e){var i;if(this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type)))return this.menu.blur(),void this.document.one("mousemove",function(){z(t.target).trigger(t.originalEvent)});i=e.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:i})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(i.value),(i=e.item.attr("aria-label")||i.value)&&z.trim(i).length&&(this.liveRegion.children().hide(),z("
        ").text(i).appendTo(this.liveRegion))},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==z.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=z("
        ",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(t){var e=this.menu.element[0];return t.target===this.element[0]||t.target===e||z.contains(e,t.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var t=this.options.appendTo;return(t=t&&(t.jquery||t.nodeType?z(t):this.document.find(t).eq(0)))&&t[0]||(t=this.element.closest(".ui-front, dialog")),t.length||(t=this.document[0].body),t},_initSource:function(){var i,s,n=this;z.isArray(this.options.source)?(i=this.options.source,this.source=function(t,e){e(z.ui.autocomplete.filter(i,t.term))}):"string"==typeof this.options.source?(s=this.options.source,this.source=function(t,e){n.xhr&&n.xhr.abort(),n.xhr=z.ajax({url:s,data:t,dataType:"json",success:function(t){e(t)},error:function(){e([])}})}):this.source=this.options.source},_searchTimeout:function(s){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),e=this.menu.element.is(":visible"),i=s.altKey||s.ctrlKey||s.metaKey||s.shiftKey;t&&(!t||e||i)||(this.selectedItem=null,this.search(null,s))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length").append(z("
        ").text(e.label)).appendTo(t)},_move:function(t,e){if(this.menu.element.is(":visible"))return this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),void this.menu.blur()):void this.menu[t](e);this.search(null,e)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){this.isMultiLine&&!this.menu.element.is(":visible")||(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),z.extend(z.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,e){var i=new RegExp(z.ui.autocomplete.escapeRegex(e),"i");return z.grep(t,function(t){return i.test(t.label||t.value||t)})}}),z.widget("ui.autocomplete",z.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(1").text(e).appendTo(this.liveRegion))}});z.ui.autocomplete}); \ No newline at end of file From f0a01587acd4a8d2a504f036b13a0b231554663d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 21:18:12 +1000 Subject: [PATCH 06/37] Rename default docker-compose file --- docker/{docker-compose.yml => docker-compose.postgresql.yml} | 2 -- 1 file changed, 2 deletions(-) rename docker/{docker-compose.yml => docker-compose.postgresql.yml} (96%) diff --git a/docker/docker-compose.yml b/docker/docker-compose.postgresql.yml similarity index 96% rename from docker/docker-compose.yml rename to docker/docker-compose.postgresql.yml index cef136bddb..2f38182418 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.postgresql.yml @@ -32,8 +32,6 @@ version: "3.8" services: # Database service # Use PostgreSQL as the database backend - # Note: this can be changed to a different backend, - # just make sure that you change the INVENTREE_DB_xxx vars below inventree-db: container_name: inventree-db image: postgres:13 From e4e735a71bd0fcd2b4550be809fd2fc6d56f68be Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 21:44:22 +1000 Subject: [PATCH 07/37] Refactoring docker-compose.postgresql.yml - Do not require duplication of username / password values - Specify different env file - Move to a new child directory which simplifies setup --- docker/{prod-config.env => production/.env} | 2 +- .../docker-compose.yml} | 12 +++--------- docker/{ => production}/nginx.conf | 0 3 files changed, 4 insertions(+), 10 deletions(-) rename docker/{prod-config.env => production/.env} (88%) rename docker/{docker-compose.postgresql.yml => production/docker-compose.yml} (90%) rename docker/{ => production}/nginx.conf (100%) diff --git a/docker/prod-config.env b/docker/production/.env similarity index 88% rename from docker/prod-config.env rename to docker/production/.env index a69fa10d2a..88eae34ebe 100644 --- a/docker/prod-config.env +++ b/docker/production/.env @@ -1,4 +1,4 @@ -# InvenTree environment variables for a production setup +# InvenTree environment variables for a postgresql production setup # Note: If your production setup varies from the example, you may want to change these values diff --git a/docker/docker-compose.postgresql.yml b/docker/production/docker-compose.yml similarity index 90% rename from docker/docker-compose.postgresql.yml rename to docker/production/docker-compose.yml index 2f38182418..abb24f5f9e 100644 --- a/docker/docker-compose.postgresql.yml +++ b/docker/production/docker-compose.yml @@ -40,9 +40,9 @@ services: environment: - PGDATA=/var/lib/postgresql/data/pgdb # The pguser and pgpassword values must be the same in the other containers - # Ensure that these are correctly configured in your prod-config.env file - - POSTGRES_USER=pguser - - POSTGRES_PASSWORD=pgpassword + # Ensure that these are correctly configured in your .env file + - POSTGRES_USER=${INVENTREE_DB_USER} + - POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD} volumes: # Map 'data' volume such that postgres database is stored externally - data:/var/lib/postgresql/data/ @@ -61,9 +61,6 @@ services: volumes: # Data volume must map to /home/inventree/data - data:/home/inventree/data - env_file: - # Environment variables required for the production server are configured in prod-config.env - - prod-config.env restart: unless-stopped # Background worker process handles long-running or periodic tasks @@ -78,9 +75,6 @@ services: volumes: # Data volume must map to /home/inventree/data - data:/home/inventree/data - env_file: - # Environment variables required for the production server are configured in prod-config.env - - prod-config.env restart: unless-stopped # nginx acts as a reverse proxy diff --git a/docker/nginx.conf b/docker/production/nginx.conf similarity index 100% rename from docker/nginx.conf rename to docker/production/nginx.conf From a50f26e84d46be7652bfda7e77b5b4355f67da43 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 21:52:25 +1000 Subject: [PATCH 08/37] Adjust naming of nginx production file --- docker/production/docker-compose.yml | 14 +++++++------- docker/production/{nginx.conf => nginx.prod.conf} | 0 2 files changed, 7 insertions(+), 7 deletions(-) rename docker/production/{nginx.conf => nginx.prod.conf} (100%) diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index abb24f5f9e..bdccd8c955 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -1,10 +1,10 @@ version: "3.8" -# Docker compose recipe for InvenTree -# - Runs PostgreSQL as the database backend -# - Runs Gunicorn as the InvenTree web server -# - Runs the InvenTree background worker process -# - Runs nginx as a reverse proxy +# Docker compose recipe for InvenTree (production setup) +# - PostgreSQL as the database backend +# - gunicorn as the InvenTree web server +# - django-q as the InvenTree background worker process +# - nginx as a reverse proxy # --------------------------------- # IMPORTANT - READ BEFORE STARTING! @@ -91,9 +91,9 @@ services: # Change "1337" to the port that you want InvenTree web server to be available on - 1337:80 volumes: - # Provide ./nginx.conf file to the container + # Provide nginx configuration file to the container # Refer to the provided example file as a starting point - - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ./nginx.prod.conf:/etc/nginx/conf.d/default.conf:ro # nginx proxy needs access to static and media files - data:/var/www restart: unless-stopped diff --git a/docker/production/nginx.conf b/docker/production/nginx.prod.conf similarity index 100% rename from docker/production/nginx.conf rename to docker/production/nginx.prod.conf From c3fff02bd8bae633290d5a0d11fa86b79ab916c7 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 22:11:07 +1000 Subject: [PATCH 09/37] Automatically create a database (with the correct name) when the db container is started! --- docker/production/docker-compose.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index bdccd8c955..b9820cc10d 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -6,6 +6,12 @@ version: "3.8" # - django-q as the InvenTree background worker process # - nginx as a reverse proxy +# --------------------------------- +# Setting environment variables +# --------------------------------- +# Shared environment variables should be stored in the .env file +# Changes made to this file are reflected across all containers! + # --------------------------------- # IMPORTANT - READ BEFORE STARTING! # --------------------------------- @@ -36,13 +42,14 @@ services: container_name: inventree-db image: postgres:13 ports: - - 5432/tcp + - ${INVENTREE_DB_PORT}/tcp environment: - PGDATA=/var/lib/postgresql/data/pgdb # The pguser and pgpassword values must be the same in the other containers # Ensure that these are correctly configured in your .env file - POSTGRES_USER=${INVENTREE_DB_USER} - POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD} + - POSTGRES_DB=${INVENTREE_DB_NAME} volumes: # Map 'data' volume such that postgres database is stored externally - data:/var/lib/postgresql/data/ @@ -58,6 +65,8 @@ services: - 8000 depends_on: - inventree-db + env_file: + - .env volumes: # Data volume must map to /home/inventree/data - data:/home/inventree/data @@ -72,6 +81,8 @@ services: depends_on: - inventree-db - inventree-server + env_file: + - .env volumes: # Data volume must map to /home/inventree/data - data:/home/inventree/data @@ -87,6 +98,8 @@ services: image: nginx:stable depends_on: - inventree-server + env_file: + - .env ports: # Change "1337" to the port that you want InvenTree web server to be available on - 1337:80 From 0b3aac21ea4880831a94199faa8219ece0f60062 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 22:35:53 +1000 Subject: [PATCH 10/37] The production docker-compose file now no longer needs to be touched at all Everything can be specified in the .env file! --- docker/production/.env | 12 ++++++- docker/production/docker-compose.yml | 50 ++++++++++++++-------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/docker/production/.env b/docker/production/.env index 88eae34ebe..16ad58427d 100644 --- a/docker/production/.env +++ b/docker/production/.env @@ -1,6 +1,16 @@ # InvenTree environment variables for a postgresql production setup -# Note: If your production setup varies from the example, you may want to change these values +# Location of persistent database data (stored external to the docker containers) +# Note: You *must* un-comment this line, and point it to a path on your local machine + +# e.g. Linux +#INVENTREE_EXT_VOLUME=/home/me/inventree-data + +# e.g. Windows (docker desktop) +#INVENTREE_EXT_VOLUME=c:/Users/me/inventree-data + +# Default web port for the InvenTree server +INVENTREE_WEB_PORT=1337 # Ensure debug is false for a production setup INVENTREE_DEBUG=False diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index b9820cc10d..5dbf4fcd73 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -6,20 +6,23 @@ version: "3.8" # - django-q as the InvenTree background worker process # - nginx as a reverse proxy -# --------------------------------- +# --------------------- +# READ BEFORE STARTING! +# --------------------- + +# ----------------------------- # Setting environment variables -# --------------------------------- +# ----------------------------- # Shared environment variables should be stored in the .env file # Changes made to this file are reflected across all containers! - -# --------------------------------- -# IMPORTANT - READ BEFORE STARTING! -# --------------------------------- -# Before running, ensure that you change the "/path/to/data" directory, -# specified in the "volumes" section at the end of this file. -# This path determines where the InvenTree data will be stored! -# # +# IMPORTANT NOTE: +# You should not have to change *anything* within the docker-compose.yml file! +# Instead, make any changes in the .env file! +# The only *mandatory* change is to set the INVENTREE_EXT_VOLUME variable, +# which defines the directory (on your local machine) where persistent data are stored. + +# ------------------------ # InvenTree Image Versions # ------------------------ # By default, this docker-compose script targets the STABLE version of InvenTree, @@ -42,17 +45,15 @@ services: container_name: inventree-db image: postgres:13 ports: - - ${INVENTREE_DB_PORT}/tcp + - ${INVENTREE_DB_PORT:-5432}/tcp environment: - PGDATA=/var/lib/postgresql/data/pgdb - # The pguser and pgpassword values must be the same in the other containers - # Ensure that these are correctly configured in your .env file - - POSTGRES_USER=${INVENTREE_DB_USER} - - POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD} - - POSTGRES_DB=${INVENTREE_DB_NAME} + - POSTGRES_USER=${INVENTREE_DB_USER:?You must provide the 'INVENTREE_DB_USER' variable in the .env file} + - POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD:?You must provide the 'INVENTREE_DB_PASSWORD' variable in the .env file} + - POSTGRES_DB=${INVENTREE_DB_NAME:?You must provide the 'INVENTREE_DB_NAME' variable in the .env file} volumes: # Map 'data' volume such that postgres database is stored externally - - data:/var/lib/postgresql/data/ + - inventree_data:/var/lib/postgresql/data/ restart: unless-stopped # InvenTree web server services @@ -69,7 +70,7 @@ services: - .env volumes: # Data volume must map to /home/inventree/data - - data:/home/inventree/data + - inventree_data:/home/inventree/data restart: unless-stopped # Background worker process handles long-running or periodic tasks @@ -85,7 +86,7 @@ services: - .env volumes: # Data volume must map to /home/inventree/data - - data:/home/inventree/data + - inventree_data:/home/inventree/data restart: unless-stopped # nginx acts as a reverse proxy @@ -101,24 +102,23 @@ services: env_file: - .env ports: - # Change "1337" to the port that you want InvenTree web server to be available on - - 1337:80 + # Default web port is 1337 (can be changed in the .env file) + - ${INVENTREE_WEB_PORT:-1337}:80 volumes: # Provide nginx configuration file to the container # Refer to the provided example file as a starting point - ./nginx.prod.conf:/etc/nginx/conf.d/default.conf:ro # nginx proxy needs access to static and media files - - data:/var/www + - inventree_data:/var/www restart: unless-stopped volumes: # NOTE: Change /path/to/data to a directory on your local machine # Persistent data, stored external to the container(s) - data: + inventree_data: driver: local driver_opts: type: none o: bind # This directory specified where InvenTree data are stored "outside" the docker containers - # Change this path to a local system path where you want InvenTree data stored - device: /path/to/data \ No newline at end of file + device: ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!} From 85feb30812953c1edfee481f2e2a72e5768962e1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 23:15:37 +1000 Subject: [PATCH 11/37] Refactor development docker-compose setup --- docker/{dev-config.env => .env} | 3 +- docker/docker-compose.sqlite.yml | 62 ------------------- ...ker-compose.dev.yml => docker-compose.yml} | 32 +++++----- docker/production/.env | 2 +- docker/production/docker-compose.yml | 2 +- docker/sqlite-config.env | 10 --- 6 files changed, 20 insertions(+), 91 deletions(-) rename docker/{dev-config.env => .env} (89%) delete mode 100644 docker/docker-compose.sqlite.yml rename docker/{docker-compose.dev.yml => docker-compose.yml} (76%) delete mode 100644 docker/sqlite-config.env diff --git a/docker/dev-config.env b/docker/.env similarity index 89% rename from docker/dev-config.env rename to docker/.env index 63a0afe4fb..2c33931c0c 100644 --- a/docker/dev-config.env +++ b/docker/.env @@ -1,6 +1,6 @@ # InvenTree environment variables for a development setup -# Set DEBUG to False for a production environment! +# Set DEBUG to True for a development setup INVENTREE_DEBUG=True INVENTREE_DEBUG_LEVEL=INFO @@ -15,3 +15,4 @@ INVENTREE_DB_PASSWORD=pgpassword # Enable plugins? INVENTREE_PLUGINS_ENABLED=True + diff --git a/docker/docker-compose.sqlite.yml b/docker/docker-compose.sqlite.yml deleted file mode 100644 index e42c43a09c..0000000000 --- a/docker/docker-compose.sqlite.yml +++ /dev/null @@ -1,62 +0,0 @@ -version: "3.8" - -# Docker compose recipe for InvenTree development server -# - Runs sqlite database -# - Uses built-in django webserver -# - Runs the InvenTree background worker process -# - Serves media and static content directly from Django webserver - -# IMPORANT NOTE: -# The InvenTree docker image does not clone source code from git. -# Instead, you must specify *where* the source code is located, -# (on your local machine). -# The django server will auto-detect any code changes and reload the server. - -services: - - # InvenTree web server services - # Uses gunicorn as the web server - inventree-dev-server: - container_name: inventree-dev-server - build: - context: . - target: dev - ports: - # Expose web server on port 8000 - - 8000:8000 - volumes: - # Ensure you specify the location of the 'src' directory at the end of this file - - src:/home/inventree - env_file: - # Environment variables required for the dev server are configured in dev-config.env - - sqlite-config.env - restart: unless-stopped - - # Background worker process handles long-running or periodic tasks - inventree-dev-worker: - container_name: inventree-dev-worker - build: - context: . - target: dev - command: invoke worker - depends_on: - - inventree-dev-server - volumes: - # Ensure you specify the location of the 'src' directory at the end of this file - - src:/home/inventree - env_file: - # Environment variables required for the dev server are configured in dev-config.env - - sqlite-config.env - restart: unless-stopped - -volumes: - # NOTE: Change "../" to a directory on your local machine, where the InvenTree source code is located - # Persistent data, stored external to the container(s) - src: - driver: local - driver_opts: - type: none - o: bind - # This directory specified where InvenTree source code is stored "outside" the docker containers - # By default, this directory is one level above the "docker" directory - device: ../ diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.yml similarity index 76% rename from docker/docker-compose.dev.yml rename to docker/docker-compose.yml index 8cbe2a9e4d..4b504fab2a 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.yml @@ -8,10 +8,12 @@ version: "3.8" # IMPORANT NOTE: # The InvenTree development image does not clone source code from git. -# Instead, you must specify *where* the source code is located, (on your local machine). -# The default setup in this file should work straight out of the box, without modification +# Instead, it runs from source code on your local machine. # The django server will auto-detect any code changes and reload the server. +# If you have cloned the InvenTree git repo, and not made any changes to this file, +# then the default setup in this file should work straight out of the box, without modification + services: # Database service @@ -21,16 +23,15 @@ services: container_name: inventree-dev-db image: postgres:13 ports: - - 5432/tcp + - ${INVENTREE_DB_PORT:-5432}/tcp environment: - - PGDATA=/var/lib/postgresql/data/dev/pgdb - # The pguser and pgpassword values must be the same in the other containers - # Ensure that these are correctly configured in your dev-config.env file - - POSTGRES_USER=pguser - - POSTGRES_PASSWORD=pgpassword + - PGDATA=/var/lib/postgresql/data/dev/pgdb + - POSTGRES_USER=${INVENTREE_DB_USER:?You must provide the 'INVENTREE_DB_USER' variable in the .env file} + - POSTGRES_PASSWORD=${INVENTREE_DB_PASSWORD:?You must provide the 'INVENTREE_DB_PASSWORD' variable in the .env file} + - POSTGRES_DB=${INVENTREE_DB_NAME:?You must provide the 'INVENTREE_DB_NAME' variable in the .env file} volumes: # Map 'data' volume such that postgres database is stored externally - - src:/var/lib/postgresql/data + - inventree_src:/var/lib/postgresql/data restart: unless-stopped # InvenTree web server services @@ -51,7 +52,7 @@ services: # - 8000 volumes: # Ensure you specify the location of the 'src' directory at the end of this file - - src:/home/inventree + - inventree_src:/home/inventree env_file: # Environment variables required for the dev server are configured in dev-config.env - dev-config.env @@ -68,7 +69,7 @@ services: - inventree-dev-server volumes: # Ensure you specify the location of the 'src' directory at the end of this file - - src:/home/inventree + - inventree_src:/home/inventree env_file: # Environment variables required for the dev server are configured in dev-config.env - dev-config.env @@ -86,21 +87,20 @@ services: # # Change "8000" to the port that you want InvenTree web server to be available on # - 8000:80 # volumes: - # # Provide ./nginx.conf file to the container + # # Provide ./nginx.dev.conf file to the container # # Refer to the provided example file as a starting point # - ./nginx.dev.conf:/etc/nginx/conf.d/default.conf:ro # # nginx proxy needs access to static and media files - # - src:/var/www + # - inventree_src:/var/www # restart: unless-stopped volumes: - # NOTE: Change "../" to a directory on your local machine, where the InvenTree source code is located # Persistent data, stored external to the container(s) - src: + inventree_src: driver: local driver_opts: type: none o: bind # This directory specified where InvenTree source code is stored "outside" the docker containers # By default, this directory is one level above the "docker" directory - device: ../ + device: ${INVENTREE_EXT_VOLUME:-../} diff --git a/docker/production/.env b/docker/production/.env index 16ad58427d..7cab3c93ee 100644 --- a/docker/production/.env +++ b/docker/production/.env @@ -12,7 +12,7 @@ # Default web port for the InvenTree server INVENTREE_WEB_PORT=1337 -# Ensure debug is false for a production setup +# Ensure DEBUG is False for a production setup INVENTREE_DEBUG=False INVENTREE_LOG_LEVEL=WARNING diff --git a/docker/production/docker-compose.yml b/docker/production/docker-compose.yml index 5dbf4fcd73..32fd3e0f48 100644 --- a/docker/production/docker-compose.yml +++ b/docker/production/docker-compose.yml @@ -1,6 +1,6 @@ version: "3.8" -# Docker compose recipe for InvenTree (production setup) +# Docker compose recipe for InvenTree production server # - PostgreSQL as the database backend # - gunicorn as the InvenTree web server # - django-q as the InvenTree background worker process diff --git a/docker/sqlite-config.env b/docker/sqlite-config.env deleted file mode 100644 index b41660ad6e..0000000000 --- a/docker/sqlite-config.env +++ /dev/null @@ -1,10 +0,0 @@ -# InvenTree environment variables for a development setup - -# Set DEBUG to False for a production environment! -INVENTREE_DEBUG=True -INVENTREE_DEBUG_LEVEL=INFO - -# Database configuration options -# Note: The example setup is for a PostgreSQL database (change as required) -INVENTREE_DB_ENGINE=sqlite -INVENTREE_DB_NAME=/home/inventree/dev/inventree_db.sqlite3 From e87e478009a77df5743cb7d0c7454fec4a01e515 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 23:34:50 +1000 Subject: [PATCH 12/37] Fix env file reference for docker-compose.yml (development) --- docker/docker-compose.yml | 6 ++---- docker/production/.env | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4b504fab2a..bfeca88336 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -54,8 +54,7 @@ services: # Ensure you specify the location of the 'src' directory at the end of this file - inventree_src:/home/inventree env_file: - # Environment variables required for the dev server are configured in dev-config.env - - dev-config.env + - .env restart: unless-stopped # Background worker process handles long-running or periodic tasks @@ -71,8 +70,7 @@ services: # Ensure you specify the location of the 'src' directory at the end of this file - inventree_src:/home/inventree env_file: - # Environment variables required for the dev server are configured in dev-config.env - - dev-config.env + - .env restart: unless-stopped ### Optional: Serve static and media files using nginx diff --git a/docker/production/.env b/docker/production/.env index 7cab3c93ee..b1c9430b51 100644 --- a/docker/production/.env +++ b/docker/production/.env @@ -12,12 +12,12 @@ # Default web port for the InvenTree server INVENTREE_WEB_PORT=1337 -# Ensure DEBUG is False for a production setup +# Ensure debug is false for a production setup INVENTREE_DEBUG=False INVENTREE_LOG_LEVEL=WARNING # Database configuration options -# Note: The example setup is for a PostgreSQL database (change as required) +# Note: The example setup is for a PostgreSQL database INVENTREE_DB_ENGINE=postgresql INVENTREE_DB_NAME=inventree INVENTREE_DB_HOST=inventree-db From 6929d07f4212abf48a2b75dd266eccb305d84a5e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 20 Apr 2022 23:52:56 +1000 Subject: [PATCH 13/37] Cache the pre-built image - The worker container can then use it - Saves a *lot* of time (and otherwise wasted resources) --- docker/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index bfeca88336..e8bb12c44a 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -43,6 +43,8 @@ services: build: context: . target: dev + # Cache the built image to be used by the inventree-dev-worker process + image: inventree-dev-image ports: # Expose web server on port 8000 - 8000:8000 @@ -60,9 +62,7 @@ services: # Background worker process handles long-running or periodic tasks inventree-dev-worker: container_name: inventree-dev-worker - build: - context: . - target: dev + image: inventree-dev-image command: invoke worker depends_on: - inventree-dev-server From 0c93009bf7e1800e97dec0e6ece11ed614eb325e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:01:11 +1000 Subject: [PATCH 14/37] Tweaks to dockerfile --- docker/Dockerfile | 4 ++-- docker/init.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 55a89210fe..b272683322 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -110,7 +110,8 @@ RUN pip3 install --user --no-cache-dir --disable-pip-version-check -r ${INVENTRE WORKDIR ${INVENTREE_MNG_DIR} # Server init entrypoint -ENTRYPOINT ["/bin/bash", "../docker/init.sh"] +COPY init.sh ${INVENTREE_HOME}/init.sh +ENTRYPOINT ["/bin/bash", "${INVENTREE_HOME}/init.sh"] # Launch the production server # TODO: Work out why environment variables cannot be interpolated in this command @@ -137,7 +138,6 @@ ENV INVENTREE_CONFIG_FILE="${INVENTREE_DEV_DIR}/config.yaml" ENV INVENTREE_SECRET_KEY_FILE="${INVENTREE_DEV_DIR}/secret_key.txt" ENV INVENTREE_PLUGIN_FILE="${INVENTREE_DEV_DIR}/plugins.txt" - WORKDIR ${INVENTREE_HOME} # Entrypoint ensures that we are running in the python virtual environment diff --git a/docker/init.sh b/docker/init.sh index 793661dc9f..088dd68e89 100644 --- a/docker/init.sh +++ b/docker/init.sh @@ -33,7 +33,7 @@ if [[ -n "$INVENTREE_PY_ENV" ]]; then source ${INVENTREE_PY_ENV}/bin/activate # Note: Python packages will have to be installed on first run - # e.g docker-compose -f docker-compose.dev.yml run inventree-dev-server invoke install + # e.g docker-compose run inventree-dev-server invoke update fi cd ${INVENTREE_HOME} From e15a4b73cda45b878ab131c59f0101b9837da7f9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:03:48 +1000 Subject: [PATCH 15/37] Restore docker-compose.sqlite.yml This is used for docker build testing in CI! --- docker/docker-compose.sqlite.yml | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docker/docker-compose.sqlite.yml diff --git a/docker/docker-compose.sqlite.yml b/docker/docker-compose.sqlite.yml new file mode 100644 index 0000000000..e42c43a09c --- /dev/null +++ b/docker/docker-compose.sqlite.yml @@ -0,0 +1,62 @@ +version: "3.8" + +# Docker compose recipe for InvenTree development server +# - Runs sqlite database +# - Uses built-in django webserver +# - Runs the InvenTree background worker process +# - Serves media and static content directly from Django webserver + +# IMPORANT NOTE: +# The InvenTree docker image does not clone source code from git. +# Instead, you must specify *where* the source code is located, +# (on your local machine). +# The django server will auto-detect any code changes and reload the server. + +services: + + # InvenTree web server services + # Uses gunicorn as the web server + inventree-dev-server: + container_name: inventree-dev-server + build: + context: . + target: dev + ports: + # Expose web server on port 8000 + - 8000:8000 + volumes: + # Ensure you specify the location of the 'src' directory at the end of this file + - src:/home/inventree + env_file: + # Environment variables required for the dev server are configured in dev-config.env + - sqlite-config.env + restart: unless-stopped + + # Background worker process handles long-running or periodic tasks + inventree-dev-worker: + container_name: inventree-dev-worker + build: + context: . + target: dev + command: invoke worker + depends_on: + - inventree-dev-server + volumes: + # Ensure you specify the location of the 'src' directory at the end of this file + - src:/home/inventree + env_file: + # Environment variables required for the dev server are configured in dev-config.env + - sqlite-config.env + restart: unless-stopped + +volumes: + # NOTE: Change "../" to a directory on your local machine, where the InvenTree source code is located + # Persistent data, stored external to the container(s) + src: + driver: local + driver_opts: + type: none + o: bind + # This directory specified where InvenTree source code is stored "outside" the docker containers + # By default, this directory is one level above the "docker" directory + device: ../ From 21445067454d66531c3b3824b8dda2cda0ed0c6d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:12:53 +1000 Subject: [PATCH 16/37] Add language support for Czech --- InvenTree/InvenTree/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index cd7290ccee..0a48a057f3 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -663,6 +663,7 @@ LANGUAGE_CODE = CONFIG.get('language', 'en-us') # If a new language translation is supported, it must be added here LANGUAGES = [ + ('cz', _('Czech')), ('de', _('German')), ('el', _('Greek')), ('en', _('English')), From 7dce7779c34a67bbb889147e32047c979d64c772 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:14:38 +1000 Subject: [PATCH 17/37] cz -> cs --- InvenTree/InvenTree/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 0a48a057f3..5b3d2eb8d8 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -663,7 +663,7 @@ LANGUAGE_CODE = CONFIG.get('language', 'en-us') # If a new language translation is supported, it must be added here LANGUAGES = [ - ('cz', _('Czech')), + ('cs', _('Czech')), ('de', _('German')), ('el', _('Greek')), ('en', _('English')), From 2b8ddd58a83c274d3ffab06177297bedc04289e2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:18:39 +1000 Subject: [PATCH 18/37] Add initial translation files --- InvenTree/locale/cs/LC_MESSAGES/django.mo | Bin 0 -> 460 bytes InvenTree/locale/cs/LC_MESSAGES/django.po | 10114 ++++++++++++++++++++ 2 files changed, 10114 insertions(+) create mode 100644 InvenTree/locale/cs/LC_MESSAGES/django.mo create mode 100644 InvenTree/locale/cs/LC_MESSAGES/django.po diff --git a/InvenTree/locale/cs/LC_MESSAGES/django.mo b/InvenTree/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..067827f3edf9b343e302b032d62ccfd3b591f1da GIT binary patch literal 460 zcmZXOK~KU!5QQ;%>d~`@F;Sw?ML-U?P^7|wjV*0TA<^3kYpp4}&2};RH%$C{{uZZ@ z$iYdz>`dN!+4pmJ@Lj>#LynLWWFNUi%4s8CDBj>(dj2NV>P;*RahGH+bdf4aA#?^0 z&X~cRMN>DJSdqw;HpDNIbV=^kNkL*o!3qNsiTAY3kRdmM!XtAc;s<2tz=+vW5kEK$}^tI4lG`|E`+gX@rbl{zOvSf(1gi_ zTBb6g(0)#h6=rMAGcr68`Z?S}9VnpKv!S^a YyEe4`+Zr2J89c@yl*uM0uRB)d7q;biga7~l literal 0 HcmV?d00001 diff --git a/InvenTree/locale/cs/LC_MESSAGES/django.po b/InvenTree/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000000..d159e9859c --- /dev/null +++ b/InvenTree/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,10114 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#: templates/js/translated/order.js:2170 +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-20 14:16+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" + +#: InvenTree/api.py:57 +msgid "API endpoint not found" +msgstr "" + +#: InvenTree/api.py:103 +msgid "No action specified" +msgstr "" + +#: InvenTree/api.py:118 +msgid "No matching action found" +msgstr "" + +#: InvenTree/fields.py:100 +msgid "Enter date" +msgstr "" + +#: InvenTree/forms.py:126 order/forms.py:24 order/forms.py:35 order/forms.py:46 +#: order/forms.py:57 templates/account/email_confirm.html:20 +#: templates/js/translated/forms.js:601 +msgid "Confirm" +msgstr "" + +#: InvenTree/forms.py:142 +msgid "Confirm delete" +msgstr "" + +#: InvenTree/forms.py:143 +msgid "Confirm item deletion" +msgstr "" + +#: InvenTree/forms.py:174 +msgid "Enter password" +msgstr "" + +#: InvenTree/forms.py:175 +msgid "Enter new password" +msgstr "" + +#: InvenTree/forms.py:182 +msgid "Confirm password" +msgstr "" + +#: InvenTree/forms.py:183 +msgid "Confirm new password" +msgstr "" + +#: InvenTree/forms.py:215 +msgid "Select Category" +msgstr "" + +#: InvenTree/forms.py:236 +msgid "Email (again)" +msgstr "" + +#: InvenTree/forms.py:240 +msgid "Email address confirmation" +msgstr "" + +#: InvenTree/forms.py:260 +msgid "You must type the same email each time." +msgstr "" + +#: InvenTree/helpers.py:442 +#, python-brace-format +msgid "Duplicate serial: {sn}" +msgstr "" + +#: InvenTree/helpers.py:449 order/models.py:282 order/models.py:435 +#: stock/views.py:993 +msgid "Invalid quantity provided" +msgstr "" + +#: InvenTree/helpers.py:452 +msgid "Empty serial number string" +msgstr "" + +#: InvenTree/helpers.py:474 InvenTree/helpers.py:477 InvenTree/helpers.py:480 +#: InvenTree/helpers.py:504 +#, python-brace-format +msgid "Invalid group: {g}" +msgstr "" + +#: InvenTree/helpers.py:518 +#, python-brace-format +msgid "Invalid/no group {group}" +msgstr "" + +#: InvenTree/helpers.py:524 +msgid "No serial numbers found" +msgstr "" + +#: InvenTree/helpers.py:528 +#, python-brace-format +msgid "Number of unique serial number ({s}) must match quantity ({q})" +msgstr "" + +#: InvenTree/models.py:185 +msgid "Missing file" +msgstr "" + +#: InvenTree/models.py:186 +msgid "Missing external link" +msgstr "" + +#: InvenTree/models.py:197 stock/models.py:2171 +#: templates/js/translated/attachment.js:119 +msgid "Attachment" +msgstr "" + +#: InvenTree/models.py:198 +msgid "Select file to attach" +msgstr "" + +#: InvenTree/models.py:204 company/models.py:131 company/models.py:348 +#: company/models.py:564 order/models.py:127 part/models.py:868 +#: report/templates/report/inventree_build_order_base.html:165 +#: templates/js/translated/company.js:540 +#: templates/js/translated/company.js:829 templates/js/translated/part.js:1423 +msgid "Link" +msgstr "" + +#: InvenTree/models.py:205 build/models.py:332 part/models.py:869 +#: stock/models.py:639 +msgid "Link to external URL" +msgstr "" + +#: InvenTree/models.py:208 templates/js/translated/attachment.js:163 +msgid "Comment" +msgstr "" + +#: InvenTree/models.py:208 +msgid "File comment" +msgstr "" + +#: InvenTree/models.py:214 InvenTree/models.py:215 common/models.py:1396 +#: common/models.py:1397 common/models.py:1618 common/models.py:1619 +#: common/models.py:1848 common/models.py:1849 part/models.py:2369 +#: part/models.py:2389 +#: report/templates/report/inventree_test_report_base.html:96 +#: templates/js/translated/stock.js:2517 +msgid "User" +msgstr "" + +#: InvenTree/models.py:218 +msgid "upload date" +msgstr "" + +#: InvenTree/models.py:241 +msgid "Filename must not be empty" +msgstr "" + +#: InvenTree/models.py:264 +msgid "Invalid attachment directory" +msgstr "" + +#: InvenTree/models.py:274 +#, python-brace-format +msgid "Filename contains illegal character '{c}'" +msgstr "" + +#: InvenTree/models.py:277 +msgid "Filename missing extension" +msgstr "" + +#: InvenTree/models.py:284 +msgid "Attachment with this filename already exists" +msgstr "" + +#: InvenTree/models.py:291 +msgid "Error renaming file" +msgstr "" + +#: InvenTree/models.py:326 +msgid "Invalid choice" +msgstr "" + +#: InvenTree/models.py:342 InvenTree/models.py:343 common/models.py:1604 +#: company/models.py:415 label/models.py:112 part/models.py:812 +#: part/models.py:2553 plugin/models.py:40 report/models.py:177 +#: templates/InvenTree/notifications/notifications.html:84 +#: templates/InvenTree/settings/mixins/urls.html:13 +#: templates/InvenTree/settings/plugin.html:49 +#: templates/InvenTree/settings/plugin.html:132 +#: templates/InvenTree/settings/plugin_settings.html:23 +#: templates/InvenTree/settings/settings.html:320 +#: templates/js/translated/company.js:641 templates/js/translated/part.js:610 +#: templates/js/translated/part.js:749 templates/js/translated/part.js:1730 +#: templates/js/translated/stock.js:2287 +msgid "Name" +msgstr "" + +#: InvenTree/models.py:349 build/models.py:209 +#: build/templates/build/detail.html:24 company/models.py:354 +#: company/models.py:570 company/templates/company/company_base.html:68 +#: company/templates/company/manufacturer_part.html:76 +#: company/templates/company/supplier_part.html:73 label/models.py:119 +#: order/models.py:125 part/models.py:835 part/templates/part/category.html:74 +#: part/templates/part/part_base.html:167 +#: part/templates/part/set_category.html:14 report/models.py:190 +#: report/models.py:553 report/models.py:592 +#: report/templates/report/inventree_build_order_base.html:118 +#: stock/templates/stock/location.html:94 +#: templates/InvenTree/settings/plugin_settings.html:33 +#: templates/js/translated/bom.js:552 templates/js/translated/bom.js:763 +#: templates/js/translated/build.js:2007 templates/js/translated/company.js:345 +#: templates/js/translated/company.js:551 +#: templates/js/translated/company.js:840 templates/js/translated/order.js:971 +#: templates/js/translated/order.js:1192 templates/js/translated/order.js:1454 +#: templates/js/translated/part.js:669 templates/js/translated/part.js:1064 +#: templates/js/translated/part.js:1337 templates/js/translated/part.js:1749 +#: templates/js/translated/part.js:1818 templates/js/translated/stock.js:1685 +#: templates/js/translated/stock.js:2299 templates/js/translated/stock.js:2354 +msgid "Description" +msgstr "" + +#: InvenTree/models.py:350 +msgid "Description (optional)" +msgstr "" + +#: InvenTree/models.py:358 +msgid "parent" +msgstr "" + +#: InvenTree/serializers.py:65 part/models.py:2872 +msgid "Must be a valid number" +msgstr "" + +#: InvenTree/serializers.py:299 +msgid "Filename" +msgstr "" + +#: InvenTree/serializers.py:334 +msgid "Invalid value" +msgstr "" + +#: InvenTree/serializers.py:355 +msgid "Data File" +msgstr "" + +#: InvenTree/serializers.py:356 +msgid "Select data file for upload" +msgstr "" + +#: InvenTree/serializers.py:380 +msgid "Unsupported file type" +msgstr "" + +#: InvenTree/serializers.py:386 +msgid "File is too large" +msgstr "" + +#: InvenTree/serializers.py:407 +msgid "No columns found in file" +msgstr "" + +#: InvenTree/serializers.py:410 +msgid "No data rows found in file" +msgstr "" + +#: InvenTree/serializers.py:533 +msgid "No data rows provided" +msgstr "" + +#: InvenTree/serializers.py:536 +msgid "No data columns supplied" +msgstr "" + +#: InvenTree/serializers.py:623 +#, python-brace-format +msgid "Missing required column: '{name}'" +msgstr "" + +#: InvenTree/serializers.py:632 +#, python-brace-format +msgid "Duplicate column: '{col}'" +msgstr "" + +#: InvenTree/settings.py:666 +msgid "Czech" +msgstr "" + +#: InvenTree/settings.py:667 +msgid "German" +msgstr "" + +#: InvenTree/settings.py:668 +msgid "Greek" +msgstr "" + +#: InvenTree/settings.py:669 +msgid "English" +msgstr "" + +#: InvenTree/settings.py:670 +msgid "Spanish" +msgstr "" + +#: InvenTree/settings.py:671 +msgid "Spanish (Mexican)" +msgstr "" + +#: InvenTree/settings.py:672 +msgid "Farsi / Persian" +msgstr "" + +#: InvenTree/settings.py:673 +msgid "French" +msgstr "" + +#: InvenTree/settings.py:674 +msgid "Hebrew" +msgstr "" + +#: InvenTree/settings.py:675 +msgid "Hungarian" +msgstr "" + +#: InvenTree/settings.py:676 +msgid "Italian" +msgstr "" + +#: InvenTree/settings.py:677 +msgid "Japanese" +msgstr "" + +#: InvenTree/settings.py:678 +msgid "Korean" +msgstr "" + +#: InvenTree/settings.py:679 +msgid "Dutch" +msgstr "" + +#: InvenTree/settings.py:680 +msgid "Norwegian" +msgstr "" + +#: InvenTree/settings.py:681 +msgid "Polish" +msgstr "" + +#: InvenTree/settings.py:682 +msgid "Portugese" +msgstr "" + +#: InvenTree/settings.py:683 +msgid "Russian" +msgstr "" + +#: InvenTree/settings.py:684 +msgid "Swedish" +msgstr "" + +#: InvenTree/settings.py:685 +msgid "Thai" +msgstr "" + +#: InvenTree/settings.py:686 +msgid "Turkish" +msgstr "" + +#: InvenTree/settings.py:687 +msgid "Vietnamese" +msgstr "" + +#: InvenTree/settings.py:688 +msgid "Chinese" +msgstr "" + +#: InvenTree/status.py:110 +msgid "Background worker check failed" +msgstr "" + +#: InvenTree/status.py:114 +msgid "Email backend not configured" +msgstr "" + +#: InvenTree/status.py:117 +msgid "InvenTree system health checks failed" +msgstr "" + +#: InvenTree/status_codes.py:101 InvenTree/status_codes.py:142 +#: InvenTree/status_codes.py:323 templates/js/translated/table_filters.js:326 +msgid "Pending" +msgstr "" + +#: InvenTree/status_codes.py:102 +msgid "Placed" +msgstr "" + +#: InvenTree/status_codes.py:103 InvenTree/status_codes.py:326 +#: order/templates/order/order_base.html:128 +#: order/templates/order/sales_order_base.html:132 +msgid "Complete" +msgstr "" + +#: InvenTree/status_codes.py:104 InvenTree/status_codes.py:144 +#: InvenTree/status_codes.py:325 +msgid "Cancelled" +msgstr "" + +#: InvenTree/status_codes.py:105 InvenTree/status_codes.py:145 +#: InvenTree/status_codes.py:187 +msgid "Lost" +msgstr "" + +#: InvenTree/status_codes.py:106 InvenTree/status_codes.py:146 +#: InvenTree/status_codes.py:189 +msgid "Returned" +msgstr "" + +#: InvenTree/status_codes.py:143 order/models.py:997 +#: templates/js/translated/order.js:2177 templates/js/translated/order.js:2474 +msgid "Shipped" +msgstr "" + +#: InvenTree/status_codes.py:183 +msgid "OK" +msgstr "" + +#: InvenTree/status_codes.py:184 +msgid "Attention needed" +msgstr "" + +#: InvenTree/status_codes.py:185 +msgid "Damaged" +msgstr "" + +#: InvenTree/status_codes.py:186 +msgid "Destroyed" +msgstr "" + +#: InvenTree/status_codes.py:188 +msgid "Rejected" +msgstr "" + +#: InvenTree/status_codes.py:276 +msgid "Legacy stock tracking entry" +msgstr "" + +#: InvenTree/status_codes.py:278 +msgid "Stock item created" +msgstr "" + +#: InvenTree/status_codes.py:280 +msgid "Edited stock item" +msgstr "" + +#: InvenTree/status_codes.py:281 +msgid "Assigned serial number" +msgstr "" + +#: InvenTree/status_codes.py:283 +msgid "Stock counted" +msgstr "" + +#: InvenTree/status_codes.py:284 +msgid "Stock manually added" +msgstr "" + +#: InvenTree/status_codes.py:285 +msgid "Stock manually removed" +msgstr "" + +#: InvenTree/status_codes.py:287 +msgid "Location changed" +msgstr "" + +#: InvenTree/status_codes.py:289 +msgid "Installed into assembly" +msgstr "" + +#: InvenTree/status_codes.py:290 +msgid "Removed from assembly" +msgstr "" + +#: InvenTree/status_codes.py:292 +msgid "Installed component item" +msgstr "" + +#: InvenTree/status_codes.py:293 +msgid "Removed component item" +msgstr "" + +#: InvenTree/status_codes.py:295 +msgid "Split from parent item" +msgstr "" + +#: InvenTree/status_codes.py:296 +msgid "Split child item" +msgstr "" + +#: InvenTree/status_codes.py:298 templates/js/translated/stock.js:2025 +msgid "Merged stock items" +msgstr "" + +#: InvenTree/status_codes.py:300 +msgid "Converted to variant" +msgstr "" + +#: InvenTree/status_codes.py:302 templates/js/translated/table_filters.js:213 +msgid "Sent to customer" +msgstr "" + +#: InvenTree/status_codes.py:303 +msgid "Returned from customer" +msgstr "" + +#: InvenTree/status_codes.py:305 +msgid "Build order output created" +msgstr "" + +#: InvenTree/status_codes.py:306 +msgid "Build order output completed" +msgstr "" + +#: InvenTree/status_codes.py:307 +msgid "Consumed by build order" +msgstr "" + +#: InvenTree/status_codes.py:309 +msgid "Received against purchase order" +msgstr "" + +#: InvenTree/status_codes.py:324 +msgid "Production" +msgstr "" + +#: InvenTree/validators.py:25 +msgid "Not a valid currency code" +msgstr "" + +#: InvenTree/validators.py:53 +msgid "Invalid character in part name" +msgstr "" + +#: InvenTree/validators.py:66 +#, python-brace-format +msgid "IPN must match regex pattern {pat}" +msgstr "" + +#: InvenTree/validators.py:80 InvenTree/validators.py:94 +#: InvenTree/validators.py:108 +#, python-brace-format +msgid "Reference must match pattern {pattern}" +msgstr "" + +#: InvenTree/validators.py:116 +#, python-brace-format +msgid "Illegal character in name ({x})" +msgstr "" + +#: InvenTree/validators.py:137 InvenTree/validators.py:153 +msgid "Overage value must not be negative" +msgstr "" + +#: InvenTree/validators.py:155 +msgid "Overage must not exceed 100%" +msgstr "" + +#: InvenTree/validators.py:162 +msgid "Invalid value for overage" +msgstr "" + +#: InvenTree/views.py:538 +msgid "Delete Item" +msgstr "" + +#: InvenTree/views.py:587 +msgid "Check box to confirm item deletion" +msgstr "" + +#: InvenTree/views.py:602 templates/InvenTree/settings/user.html:21 +msgid "Edit User Information" +msgstr "" + +#: InvenTree/views.py:613 templates/InvenTree/settings/user.html:19 +msgid "Set Password" +msgstr "" + +#: InvenTree/views.py:632 +msgid "Password fields must match" +msgstr "" + +#: InvenTree/views.py:883 templates/navbar.html:144 +msgid "System Information" +msgstr "" + +#: barcodes/api.py:55 barcodes/api.py:156 +msgid "Must provide barcode_data parameter" +msgstr "" + +#: barcodes/api.py:132 +msgid "No match found for barcode data" +msgstr "" + +#: barcodes/api.py:134 +msgid "Match found for barcode data" +msgstr "" + +#: barcodes/api.py:159 +msgid "Must provide stockitem parameter" +msgstr "" + +#: barcodes/api.py:166 +msgid "No matching stock item found" +msgstr "" + +#: barcodes/api.py:197 +msgid "Barcode already matches Stock Item" +msgstr "" + +#: barcodes/api.py:201 +msgid "Barcode already matches Stock Location" +msgstr "" + +#: barcodes/api.py:205 +msgid "Barcode already matches Part" +msgstr "" + +#: barcodes/api.py:211 barcodes/api.py:223 +msgid "Barcode hash already matches Stock Item" +msgstr "" + +#: barcodes/api.py:229 +msgid "Barcode associated with Stock Item" +msgstr "" + +#: build/forms.py:20 +msgid "Confirm cancel" +msgstr "" + +#: build/forms.py:20 build/views.py:62 +msgid "Confirm build cancellation" +msgstr "" + +#: build/models.py:135 +msgid "Invalid choice for parent build" +msgstr "" + +#: build/models.py:139 build/templates/build/build_base.html:9 +#: build/templates/build/build_base.html:27 +#: report/templates/report/inventree_build_order_base.html:106 +#: templates/js/translated/build.js:677 +msgid "Build Order" +msgstr "" + +#: build/models.py:140 build/templates/build/build_base.html:13 +#: build/templates/build/index.html:8 build/templates/build/index.html:12 +#: order/templates/order/sales_order_detail.html:91 +#: order/templates/order/so_sidebar.html:13 +#: part/templates/part/part_sidebar.html:23 templates/InvenTree/index.html:221 +#: templates/InvenTree/search.html:139 +#: templates/InvenTree/settings/sidebar.html:45 users/models.py:44 +msgid "Build Orders" +msgstr "" + +#: build/models.py:200 +msgid "Build Order Reference" +msgstr "" + +#: build/models.py:201 order/models.py:213 order/models.py:563 +#: order/models.py:843 part/models.py:2783 +#: part/templates/part/upload_bom.html:54 +#: report/templates/report/inventree_po_report.html:91 +#: report/templates/report/inventree_so_report.html:92 +#: templates/js/translated/bom.js:770 templates/js/translated/build.js:1415 +#: templates/js/translated/order.js:1223 templates/js/translated/order.js:2341 +msgid "Reference" +msgstr "" + +#: build/models.py:212 +msgid "Brief description of the build" +msgstr "" + +#: build/models.py:221 build/templates/build/build_base.html:169 +#: build/templates/build/detail.html:87 +msgid "Parent Build" +msgstr "" + +#: build/models.py:222 +msgid "BuildOrder to which this build is allocated" +msgstr "" + +#: build/models.py:227 build/templates/build/build_base.html:77 +#: build/templates/build/detail.html:29 company/models.py:706 +#: order/models.py:912 order/models.py:986 +#: order/templates/order/order_wizard/select_parts.html:32 part/models.py:367 +#: part/models.py:2315 part/models.py:2331 part/models.py:2350 +#: part/models.py:2367 part/models.py:2469 part/models.py:2591 +#: part/models.py:2681 part/models.py:2758 part/models.py:3048 +#: part/serializers.py:834 part/templates/part/part_app_base.html:8 +#: part/templates/part/part_pricing.html:12 +#: part/templates/part/set_category.html:13 +#: part/templates/part/upload_bom.html:52 +#: report/templates/report/inventree_build_order_base.html:110 +#: report/templates/report/inventree_po_report.html:89 +#: report/templates/report/inventree_so_report.html:90 +#: templates/InvenTree/search.html:80 +#: templates/email/build_order_required_stock.html:17 +#: templates/email/low_stock_notification.html:16 +#: templates/js/translated/barcode.js:382 templates/js/translated/bom.js:551 +#: templates/js/translated/bom.js:728 templates/js/translated/build.js:903 +#: templates/js/translated/build.js:1284 templates/js/translated/build.js:1699 +#: templates/js/translated/build.js:2012 templates/js/translated/company.js:492 +#: templates/js/translated/company.js:749 templates/js/translated/order.js:84 +#: templates/js/translated/order.js:711 templates/js/translated/order.js:1177 +#: templates/js/translated/order.js:1781 templates/js/translated/order.js:2130 +#: templates/js/translated/order.js:2325 templates/js/translated/part.js:1049 +#: templates/js/translated/part.js:1119 templates/js/translated/part.js:1315 +#: templates/js/translated/stock.js:530 templates/js/translated/stock.js:695 +#: templates/js/translated/stock.js:902 templates/js/translated/stock.js:1642 +#: templates/js/translated/stock.js:2380 templates/js/translated/stock.js:2575 +#: templates/js/translated/stock.js:2675 +msgid "Part" +msgstr "" + +#: build/models.py:235 +msgid "Select part to build" +msgstr "" + +#: build/models.py:240 +msgid "Sales Order Reference" +msgstr "" + +#: build/models.py:244 +msgid "SalesOrder to which this build is allocated" +msgstr "" + +#: build/models.py:249 build/serializers.py:730 +#: templates/js/translated/build.js:1687 templates/js/translated/order.js:1769 +msgid "Source Location" +msgstr "" + +#: build/models.py:253 +msgid "Select location to take stock from for this build (leave blank to take from any stock location)" +msgstr "" + +#: build/models.py:258 +msgid "Destination Location" +msgstr "" + +#: build/models.py:262 +msgid "Select location where the completed items will be stored" +msgstr "" + +#: build/models.py:266 +msgid "Build Quantity" +msgstr "" + +#: build/models.py:269 +msgid "Number of stock items to build" +msgstr "" + +#: build/models.py:273 +msgid "Completed items" +msgstr "" + +#: build/models.py:275 +msgid "Number of stock items which have been completed" +msgstr "" + +#: build/models.py:279 +msgid "Build Status" +msgstr "" + +#: build/models.py:283 +msgid "Build status code" +msgstr "" + +#: build/models.py:287 build/serializers.py:218 order/serializers.py:272 +#: stock/models.py:643 templates/js/translated/order.js:573 +msgid "Batch Code" +msgstr "" + +#: build/models.py:291 build/serializers.py:219 +msgid "Batch code for this build output" +msgstr "" + +#: build/models.py:294 order/models.py:129 part/models.py:1007 +#: part/templates/part/part_base.html:331 templates/js/translated/order.js:1467 +msgid "Creation Date" +msgstr "" + +#: build/models.py:298 order/models.py:585 +msgid "Target completion date" +msgstr "" + +#: build/models.py:299 +msgid "Target date for build completion. Build will be overdue after this date." +msgstr "" + +#: build/models.py:302 order/models.py:255 +#: templates/js/translated/build.js:2089 +msgid "Completion Date" +msgstr "" + +#: build/models.py:308 +msgid "completed by" +msgstr "" + +#: build/models.py:316 templates/js/translated/build.js:2057 +msgid "Issued by" +msgstr "" + +#: build/models.py:317 +msgid "User who issued this build order" +msgstr "" + +#: build/models.py:325 build/templates/build/build_base.html:190 +#: build/templates/build/detail.html:115 order/models.py:143 +#: order/templates/order/order_base.html:170 +#: order/templates/order/sales_order_base.html:182 part/models.py:1011 +#: report/templates/report/inventree_build_order_base.html:159 +#: templates/js/translated/build.js:2069 templates/js/translated/order.js:1005 +msgid "Responsible" +msgstr "" + +#: build/models.py:326 +msgid "User responsible for this build order" +msgstr "" + +#: build/models.py:331 build/templates/build/detail.html:101 +#: company/templates/company/manufacturer_part.html:102 +#: company/templates/company/supplier_part.html:126 +#: part/templates/part/part_base.html:372 stock/models.py:637 +#: stock/templates/stock/item_base.html:357 +msgid "External Link" +msgstr "" + +#: build/models.py:336 build/serializers.py:381 +#: build/templates/build/sidebar.html:21 company/models.py:142 +#: company/models.py:577 company/templates/company/sidebar.html:25 +#: order/models.py:147 order/models.py:845 order/models.py:1107 +#: order/templates/order/po_sidebar.html:11 +#: order/templates/order/so_sidebar.html:17 part/models.py:996 +#: part/templates/part/part_sidebar.html:60 +#: report/templates/report/inventree_build_order_base.html:173 +#: stock/forms.py:137 stock/forms.py:171 stock/models.py:709 +#: stock/models.py:2071 stock/models.py:2177 stock/serializers.py:332 +#: stock/serializers.py:697 stock/serializers.py:795 stock/serializers.py:927 +#: stock/templates/stock/stock_sidebar.html:25 +#: templates/js/translated/barcode.js:58 templates/js/translated/bom.js:944 +#: templates/js/translated/company.js:845 templates/js/translated/order.js:1344 +#: templates/js/translated/order.js:1650 templates/js/translated/order.js:2499 +#: templates/js/translated/stock.js:1316 templates/js/translated/stock.js:1921 +msgid "Notes" +msgstr "" + +#: build/models.py:337 +msgid "Extra build notes" +msgstr "" + +#: build/models.py:750 +msgid "No build output specified" +msgstr "" + +#: build/models.py:753 +msgid "Build output is already completed" +msgstr "" + +#: build/models.py:756 +msgid "Build output does not match Build Order" +msgstr "" + +#: build/models.py:1168 +msgid "Build item must specify a build output, as master part is marked as trackable" +msgstr "" + +#: build/models.py:1177 +#, python-brace-format +msgid "Allocated quantity ({q}) must not execed available stock quantity ({a})" +msgstr "" + +#: build/models.py:1187 +msgid "Stock item is over-allocated" +msgstr "" + +#: build/models.py:1193 order/models.py:1225 +msgid "Allocation quantity must be greater than zero" +msgstr "" + +#: build/models.py:1199 +msgid "Quantity must be 1 for serialized stock" +msgstr "" + +#: build/models.py:1256 +msgid "Selected stock item not found in BOM" +msgstr "" + +#: build/models.py:1325 stock/templates/stock/item_base.html:329 +#: templates/InvenTree/search.html:137 templates/js/translated/build.js:1985 +#: templates/navbar.html:35 +msgid "Build" +msgstr "" + +#: build/models.py:1326 +msgid "Build to allocate parts" +msgstr "" + +#: build/models.py:1342 build/serializers.py:576 order/serializers.py:783 +#: order/serializers.py:801 stock/serializers.py:404 stock/serializers.py:635 +#: stock/serializers.py:753 stock/templates/stock/item_base.html:9 +#: stock/templates/stock/item_base.html:23 +#: stock/templates/stock/item_base.html:351 +#: templates/js/translated/build.js:688 templates/js/translated/build.js:693 +#: templates/js/translated/build.js:1701 templates/js/translated/build.js:2137 +#: templates/js/translated/order.js:85 templates/js/translated/order.js:1782 +#: templates/js/translated/order.js:2037 templates/js/translated/order.js:2042 +#: templates/js/translated/order.js:2137 templates/js/translated/order.js:2227 +#: templates/js/translated/stock.js:531 templates/js/translated/stock.js:696 +#: templates/js/translated/stock.js:2453 +msgid "Stock Item" +msgstr "" + +#: build/models.py:1343 +msgid "Source stock item" +msgstr "" + +#: build/models.py:1355 build/serializers.py:188 +#: build/templates/build/build_base.html:82 +#: build/templates/build/detail.html:34 common/models.py:1429 +#: company/forms.py:42 company/templates/company/supplier_part.html:251 +#: order/models.py:836 order/models.py:1265 order/serializers.py:903 +#: order/templates/order/order_wizard/match_parts.html:30 +#: order/templates/order/order_wizard/select_parts.html:34 part/forms.py:144 +#: part/forms.py:160 part/forms.py:176 part/models.py:2774 +#: part/templates/part/detail.html:965 part/templates/part/detail.html:1051 +#: part/templates/part/part_pricing.html:16 +#: part/templates/part/upload_bom.html:53 +#: report/templates/report/inventree_build_order_base.html:114 +#: report/templates/report/inventree_po_report.html:90 +#: report/templates/report/inventree_so_report.html:91 +#: report/templates/report/inventree_test_report_base.html:81 +#: report/templates/report/inventree_test_report_base.html:139 +#: stock/forms.py:139 stock/serializers.py:293 +#: stock/templates/stock/item_base.html:181 +#: stock/templates/stock/item_base.html:246 +#: stock/templates/stock/item_base.html:254 +#: templates/js/translated/barcode.js:384 templates/js/translated/bom.js:778 +#: templates/js/translated/build.js:376 templates/js/translated/build.js:524 +#: templates/js/translated/build.js:715 templates/js/translated/build.js:912 +#: templates/js/translated/build.js:922 templates/js/translated/build.js:1311 +#: templates/js/translated/build.js:1702 +#: templates/js/translated/model_renderers.js:108 +#: templates/js/translated/order.js:101 templates/js/translated/order.js:1229 +#: templates/js/translated/order.js:1783 templates/js/translated/order.js:2056 +#: templates/js/translated/order.js:2144 templates/js/translated/order.js:2233 +#: templates/js/translated/order.js:2347 templates/js/translated/part.js:949 +#: templates/js/translated/part.js:1961 templates/js/translated/part.js:2183 +#: templates/js/translated/part.js:2217 templates/js/translated/part.js:2295 +#: templates/js/translated/stock.js:402 templates/js/translated/stock.js:556 +#: templates/js/translated/stock.js:726 templates/js/translated/stock.js:2502 +#: templates/js/translated/stock.js:2587 +msgid "Quantity" +msgstr "" + +#: build/models.py:1356 +msgid "Stock quantity to allocate to build" +msgstr "" + +#: build/models.py:1364 +msgid "Install into" +msgstr "" + +#: build/models.py:1365 +msgid "Destination stock item" +msgstr "" + +#: build/serializers.py:138 build/serializers.py:605 +msgid "Build Output" +msgstr "" + +#: build/serializers.py:150 +msgid "Build output does not match the parent build" +msgstr "" + +#: build/serializers.py:154 +msgid "Output part does not match BuildOrder part" +msgstr "" + +#: build/serializers.py:158 +msgid "This build output has already been completed" +msgstr "" + +#: build/serializers.py:164 +msgid "This build output is not fully allocated" +msgstr "" + +#: build/serializers.py:189 +msgid "Enter quantity for build output" +msgstr "" + +#: build/serializers.py:201 build/serializers.py:596 order/models.py:280 +#: order/serializers.py:267 part/serializers.py:556 part/serializers.py:1001 +#: stock/models.py:477 stock/models.py:1280 stock/serializers.py:305 +msgid "Quantity must be greater than zero" +msgstr "" + +#: build/serializers.py:208 +msgid "Integer quantity required for trackable parts" +msgstr "" + +#: build/serializers.py:211 +msgid "Integer quantity required, as the bill of materials contains trackable parts" +msgstr "" + +#: build/serializers.py:225 order/serializers.py:280 order/serializers.py:907 +#: stock/forms.py:78 stock/serializers.py:314 +#: templates/js/translated/order.js:584 templates/js/translated/stock.js:237 +#: templates/js/translated/stock.js:403 +msgid "Serial Numbers" +msgstr "" + +#: build/serializers.py:226 +msgid "Enter serial numbers for build outputs" +msgstr "" + +#: build/serializers.py:240 +msgid "Auto Allocate Serial Numbers" +msgstr "" + +#: build/serializers.py:241 +msgid "Automatically allocate required items with matching serial numbers" +msgstr "" + +#: build/serializers.py:275 stock/api.py:591 +msgid "The following serial numbers already exist" +msgstr "" + +#: build/serializers.py:328 build/serializers.py:393 +msgid "A list of build outputs must be provided" +msgstr "" + +#: build/serializers.py:370 order/serializers.py:253 order/serializers.py:358 +#: stock/forms.py:169 stock/serializers.py:325 stock/serializers.py:788 +#: stock/serializers.py:1029 stock/templates/stock/item_base.html:297 +#: templates/js/translated/barcode.js:383 +#: templates/js/translated/barcode.js:565 templates/js/translated/build.js:700 +#: templates/js/translated/build.js:1323 templates/js/translated/order.js:611 +#: templates/js/translated/order.js:2049 templates/js/translated/order.js:2152 +#: templates/js/translated/order.js:2160 templates/js/translated/order.js:2241 +#: templates/js/translated/part.js:180 templates/js/translated/stock.js:532 +#: templates/js/translated/stock.js:697 templates/js/translated/stock.js:904 +#: templates/js/translated/stock.js:1792 templates/js/translated/stock.js:2394 +msgid "Location" +msgstr "" + +#: build/serializers.py:371 +msgid "Location for completed build outputs" +msgstr "" + +#: build/serializers.py:377 build/templates/build/build_base.html:142 +#: build/templates/build/detail.html:62 order/models.py:579 +#: order/serializers.py:290 stock/templates/stock/item_base.html:187 +#: templates/js/translated/barcode.js:140 templates/js/translated/build.js:2041 +#: templates/js/translated/order.js:716 templates/js/translated/order.js:975 +#: templates/js/translated/order.js:1459 templates/js/translated/stock.js:1767 +#: templates/js/translated/stock.js:2471 templates/js/translated/stock.js:2603 +msgid "Status" +msgstr "" + +#: build/serializers.py:434 +msgid "Accept Unallocated" +msgstr "" + +#: build/serializers.py:435 +msgid "Accept that stock items have not been fully allocated to this build order" +msgstr "" + +#: build/serializers.py:445 templates/js/translated/build.js:151 +msgid "Required stock has not been fully allocated" +msgstr "" + +#: build/serializers.py:450 +msgid "Accept Incomplete" +msgstr "" + +#: build/serializers.py:451 +msgid "Accept that the required number of build outputs have not been completed" +msgstr "" + +#: build/serializers.py:461 templates/js/translated/build.js:155 +msgid "Required build quantity has not been completed" +msgstr "" + +#: build/serializers.py:470 +msgid "Build order has incomplete outputs" +msgstr "" + +#: build/serializers.py:473 build/templates/build/build_base.html:95 +msgid "No build outputs have been created for this build order" +msgstr "" + +#: build/serializers.py:501 build/serializers.py:550 part/models.py:2898 +#: part/models.py:3040 +msgid "BOM Item" +msgstr "" + +#: build/serializers.py:511 +msgid "Build output" +msgstr "" + +#: build/serializers.py:520 +msgid "Build output must point to the same build" +msgstr "" + +#: build/serializers.py:567 +msgid "bom_item.part must point to the same part as the build order" +msgstr "" + +#: build/serializers.py:582 stock/serializers.py:642 +msgid "Item must be in stock" +msgstr "" + +#: build/serializers.py:638 order/serializers.py:834 +#, python-brace-format +msgid "Available quantity ({q}) exceeded" +msgstr "" + +#: build/serializers.py:644 +msgid "Build output must be specified for allocation of tracked parts" +msgstr "" + +#: build/serializers.py:651 +msgid "Build output cannot be specified for allocation of untracked parts" +msgstr "" + +#: build/serializers.py:679 order/serializers.py:1077 +msgid "Allocation items must be provided" +msgstr "" + +#: build/serializers.py:731 +msgid "Stock location where parts are to be sourced (leave blank to take from any location)" +msgstr "" + +#: build/serializers.py:739 +msgid "Exclude Location" +msgstr "" + +#: build/serializers.py:740 +msgid "Exclude stock items from this selected location" +msgstr "" + +#: build/serializers.py:745 +msgid "Interchangeable Stock" +msgstr "" + +#: build/serializers.py:746 +msgid "Stock items in multiple locations can be used interchangeably" +msgstr "" + +#: build/serializers.py:751 +msgid "Substitute Stock" +msgstr "" + +#: build/serializers.py:752 +msgid "Allow allocation of substitute parts" +msgstr "" + +#: build/tasks.py:98 +msgid "Stock required for build order" +msgstr "" + +#: build/templates/build/build_base.html:39 +#: order/templates/order/order_base.html:28 +#: order/templates/order/sales_order_base.html:38 +msgid "Print actions" +msgstr "" + +#: build/templates/build/build_base.html:43 +msgid "Print build order report" +msgstr "" + +#: build/templates/build/build_base.html:50 +msgid "Build actions" +msgstr "" + +#: build/templates/build/build_base.html:54 +msgid "Edit Build" +msgstr "" + +#: build/templates/build/build_base.html:56 +#: build/templates/build/build_base.html:220 build/views.py:53 +msgid "Cancel Build" +msgstr "" + +#: build/templates/build/build_base.html:59 +msgid "Delete Build" +msgstr "" + +#: build/templates/build/build_base.html:64 +#: build/templates/build/build_base.html:65 +msgid "Complete Build" +msgstr "" + +#: build/templates/build/build_base.html:87 +msgid "Build Description" +msgstr "" + +#: build/templates/build/build_base.html:101 +#, python-format +msgid "This Build Order is allocated to Sales Order %(link)s" +msgstr "" + +#: build/templates/build/build_base.html:108 +#, python-format +msgid "This Build Order is a child of Build Order %(link)s" +msgstr "" + +#: build/templates/build/build_base.html:115 +msgid "Build Order is ready to mark as completed" +msgstr "" + +#: build/templates/build/build_base.html:120 +msgid "Build Order cannot be completed as outstanding outputs remain" +msgstr "" + +#: build/templates/build/build_base.html:125 +msgid "Required build quantity has not yet been completed" +msgstr "" + +#: build/templates/build/build_base.html:130 +msgid "Stock has not been fully allocated to this Build Order" +msgstr "" + +#: build/templates/build/build_base.html:151 +#: build/templates/build/detail.html:131 order/models.py:849 +#: order/templates/order/order_base.html:156 +#: order/templates/order/sales_order_base.html:163 +#: report/templates/report/inventree_build_order_base.html:126 +#: templates/js/translated/build.js:2081 templates/js/translated/order.js:992 +#: templates/js/translated/order.js:1291 templates/js/translated/order.js:1475 +#: templates/js/translated/order.js:2410 templates/js/translated/part.js:953 +msgid "Target Date" +msgstr "" + +#: build/templates/build/build_base.html:156 +#, python-format +msgid "This build was due on %(target)s" +msgstr "" + +#: build/templates/build/build_base.html:156 +#: build/templates/build/build_base.html:201 +#: order/templates/order/order_base.html:98 +#: order/templates/order/sales_order_base.html:93 +#: templates/js/translated/table_filters.js:312 +#: templates/js/translated/table_filters.js:353 +#: templates/js/translated/table_filters.js:383 +msgid "Overdue" +msgstr "" + +#: build/templates/build/build_base.html:163 +#: build/templates/build/detail.html:67 build/templates/build/detail.html:142 +#: order/templates/order/sales_order_base.html:170 +#: templates/js/translated/build.js:2027 +#: templates/js/translated/table_filters.js:392 +msgid "Completed" +msgstr "" + +#: build/templates/build/build_base.html:176 +#: build/templates/build/detail.html:94 order/models.py:983 +#: order/models.py:1079 order/templates/order/sales_order_base.html:9 +#: order/templates/order/sales_order_base.html:28 +#: report/templates/report/inventree_build_order_base.html:136 +#: report/templates/report/inventree_so_report.html:77 +#: stock/templates/stock/item_base.html:291 +#: templates/js/translated/order.js:1414 +msgid "Sales Order" +msgstr "" + +#: build/templates/build/build_base.html:183 +#: build/templates/build/detail.html:108 +#: report/templates/report/inventree_build_order_base.html:153 +msgid "Issued By" +msgstr "" + +#: build/templates/build/build_base.html:228 +#: build/templates/build/sidebar.html:12 +msgid "Incomplete Outputs" +msgstr "" + +#: build/templates/build/build_base.html:229 +msgid "Build Order cannot be completed as incomplete build outputs remain" +msgstr "" + +#: build/templates/build/cancel.html:5 +msgid "Are you sure you wish to cancel this build?" +msgstr "" + +#: build/templates/build/delete_build.html:5 +msgid "Are you sure you want to delete this build?" +msgstr "" + +#: build/templates/build/detail.html:15 +msgid "Build Details" +msgstr "" + +#: build/templates/build/detail.html:38 +msgid "Stock Source" +msgstr "" + +#: build/templates/build/detail.html:43 +msgid "Stock can be taken from any available location." +msgstr "" + +#: build/templates/build/detail.html:49 order/models.py:934 stock/forms.py:133 +#: templates/js/translated/order.js:717 templates/js/translated/order.js:1333 +msgid "Destination" +msgstr "" + +#: build/templates/build/detail.html:56 +msgid "Destination location not specified" +msgstr "" + +#: build/templates/build/detail.html:73 templates/js/translated/build.js:930 +msgid "Allocated Parts" +msgstr "" + +#: build/templates/build/detail.html:80 +#: stock/templates/stock/item_base.html:315 +#: templates/js/translated/model_renderers.js:112 +#: templates/js/translated/stock.js:970 templates/js/translated/stock.js:1781 +#: templates/js/translated/stock.js:2610 +#: templates/js/translated/table_filters.js:151 +#: templates/js/translated/table_filters.js:242 +msgid "Batch" +msgstr "" + +#: build/templates/build/detail.html:126 +#: order/templates/order/order_base.html:143 +#: order/templates/order/sales_order_base.html:157 +#: templates/js/translated/build.js:2049 +msgid "Created" +msgstr "" + +#: build/templates/build/detail.html:137 +msgid "No target date set" +msgstr "" + +#: build/templates/build/detail.html:146 +msgid "Build not complete" +msgstr "" + +#: build/templates/build/detail.html:157 build/templates/build/sidebar.html:17 +msgid "Child Build Orders" +msgstr "" + +#: build/templates/build/detail.html:172 +msgid "Allocate Stock to Build" +msgstr "" + +#: build/templates/build/detail.html:176 templates/js/translated/build.js:1515 +msgid "Unallocate stock" +msgstr "" + +#: build/templates/build/detail.html:177 +msgid "Unallocate Stock" +msgstr "" + +#: build/templates/build/detail.html:179 +msgid "Automatically allocate stock to build" +msgstr "" + +#: build/templates/build/detail.html:180 +msgid "Auto Allocate" +msgstr "" + +#: build/templates/build/detail.html:182 +msgid "Manually allocate stock to build" +msgstr "" + +#: build/templates/build/detail.html:183 build/templates/build/sidebar.html:8 +msgid "Allocate Stock" +msgstr "" + +#: build/templates/build/detail.html:186 +msgid "Order required parts" +msgstr "" + +#: build/templates/build/detail.html:187 +#: company/templates/company/detail.html:37 +#: company/templates/company/detail.html:84 order/views.py:463 +#: part/templates/part/category.html:174 +msgid "Order Parts" +msgstr "" + +#: build/templates/build/detail.html:199 +msgid "Untracked stock has been fully allocated for this Build Order" +msgstr "" + +#: build/templates/build/detail.html:203 +msgid "Untracked stock has not been fully allocated for this Build Order" +msgstr "" + +#: build/templates/build/detail.html:210 +msgid "Allocate selected items" +msgstr "" + +#: build/templates/build/detail.html:220 +msgid "This Build Order does not have any associated untracked BOM items" +msgstr "" + +#: build/templates/build/detail.html:229 +msgid "Incomplete Build Outputs" +msgstr "" + +#: build/templates/build/detail.html:233 +msgid "Create new build output" +msgstr "" + +#: build/templates/build/detail.html:234 +msgid "New Build Output" +msgstr "" + +#: build/templates/build/detail.html:248 +msgid "Output Actions" +msgstr "" + +#: build/templates/build/detail.html:252 +msgid "Complete selected build outputs" +msgstr "" + +#: build/templates/build/detail.html:253 +msgid "Complete outputs" +msgstr "" + +#: build/templates/build/detail.html:255 +msgid "Delete selected build outputs" +msgstr "" + +#: build/templates/build/detail.html:256 +msgid "Delete outputs" +msgstr "" + +#: build/templates/build/detail.html:263 +#: stock/templates/stock/location.html:188 templates/stock_table.html:27 +msgid "Printing Actions" +msgstr "" + +#: build/templates/build/detail.html:267 build/templates/build/detail.html:268 +#: stock/templates/stock/location.html:192 templates/stock_table.html:31 +msgid "Print labels" +msgstr "" + +#: build/templates/build/detail.html:285 +msgid "Completed Build Outputs" +msgstr "" + +#: build/templates/build/detail.html:297 build/templates/build/sidebar.html:19 +#: order/templates/order/po_sidebar.html:9 +#: order/templates/order/purchase_order_detail.html:59 +#: order/templates/order/sales_order_detail.html:106 +#: order/templates/order/so_sidebar.html:15 part/templates/part/detail.html:206 +#: part/templates/part/part_sidebar.html:58 stock/templates/stock/item.html:122 +#: stock/templates/stock/stock_sidebar.html:23 +msgid "Attachments" +msgstr "" + +#: build/templates/build/detail.html:312 +msgid "Build Notes" +msgstr "" + +#: build/templates/build/detail.html:548 +msgid "Allocation Complete" +msgstr "" + +#: build/templates/build/detail.html:549 +msgid "All untracked stock items have been allocated" +msgstr "" + +#: build/templates/build/index.html:18 part/templates/part/detail.html:312 +msgid "New Build Order" +msgstr "" + +#: build/templates/build/index.html:37 build/templates/build/index.html:38 +msgid "Print Build Orders" +msgstr "" + +#: build/templates/build/index.html:44 +#: order/templates/order/purchase_orders.html:34 +#: order/templates/order/sales_orders.html:37 +msgid "Display calendar view" +msgstr "" + +#: build/templates/build/index.html:47 +#: order/templates/order/purchase_orders.html:37 +#: order/templates/order/sales_orders.html:40 +msgid "Display list view" +msgstr "" + +#: build/templates/build/sidebar.html:5 +msgid "Build Order Details" +msgstr "" + +#: build/templates/build/sidebar.html:15 +msgid "Completed Outputs" +msgstr "" + +#: build/views.py:73 +msgid "Build was cancelled" +msgstr "" + +#: build/views.py:114 +msgid "Delete Build Order" +msgstr "" + +#: common/files.py:65 +msgid "Unsupported file format: {ext.upper()}" +msgstr "" + +#: common/files.py:67 +msgid "Error reading file (invalid encoding)" +msgstr "" + +#: common/files.py:72 +msgid "Error reading file (invalid format)" +msgstr "" + +#: common/files.py:74 +msgid "Error reading file (incorrect dimension)" +msgstr "" + +#: common/files.py:76 +msgid "Error reading file (data could be corrupted)" +msgstr "" + +#: common/forms.py:34 +msgid "File" +msgstr "" + +#: common/forms.py:35 +msgid "Select file to upload" +msgstr "" + +#: common/forms.py:50 +msgid "{name.title()} File" +msgstr "" + +#: common/forms.py:51 +#, python-brace-format +msgid "Select {name} file to upload" +msgstr "" + +#: common/models.py:381 +msgid "Settings key (must be unique - case insensitive)" +msgstr "" + +#: common/models.py:383 +msgid "Settings value" +msgstr "" + +#: common/models.py:417 +msgid "Chosen value is not a valid option" +msgstr "" + +#: common/models.py:437 +msgid "Value must be a boolean value" +msgstr "" + +#: common/models.py:448 +msgid "Value must be an integer value" +msgstr "" + +#: common/models.py:490 +msgid "Key string must be unique" +msgstr "" + +#: common/models.py:637 +msgid "No group" +msgstr "" + +#: common/models.py:679 +msgid "Restart required" +msgstr "" + +#: common/models.py:680 +msgid "A setting has been changed which requires a server restart" +msgstr "" + +#: common/models.py:687 +msgid "InvenTree Instance Name" +msgstr "" + +#: common/models.py:689 +msgid "String descriptor for the server instance" +msgstr "" + +#: common/models.py:693 +msgid "Use instance name" +msgstr "" + +#: common/models.py:694 +msgid "Use the instance name in the title-bar" +msgstr "" + +#: common/models.py:700 company/models.py:100 company/models.py:101 +msgid "Company name" +msgstr "" + +#: common/models.py:701 +msgid "Internal company name" +msgstr "" + +#: common/models.py:706 +msgid "Base URL" +msgstr "" + +#: common/models.py:707 +msgid "Base URL for server instance" +msgstr "" + +#: common/models.py:713 +msgid "Default Currency" +msgstr "" + +#: common/models.py:714 +msgid "Default currency" +msgstr "" + +#: common/models.py:720 +msgid "Download from URL" +msgstr "" + +#: common/models.py:721 +msgid "Allow download of remote images and files from external URL" +msgstr "" + +#: common/models.py:727 templates/InvenTree/settings/sidebar.html:33 +msgid "Barcode Support" +msgstr "" + +#: common/models.py:728 +msgid "Enable barcode scanner support" +msgstr "" + +#: common/models.py:734 +msgid "IPN Regex" +msgstr "" + +#: common/models.py:735 +msgid "Regular expression pattern for matching Part IPN" +msgstr "" + +#: common/models.py:739 +msgid "Allow Duplicate IPN" +msgstr "" + +#: common/models.py:740 +msgid "Allow multiple parts to share the same IPN" +msgstr "" + +#: common/models.py:746 +msgid "Allow Editing IPN" +msgstr "" + +#: common/models.py:747 +msgid "Allow changing the IPN value while editing a part" +msgstr "" + +#: common/models.py:753 +msgid "Copy Part BOM Data" +msgstr "" + +#: common/models.py:754 +msgid "Copy BOM data by default when duplicating a part" +msgstr "" + +#: common/models.py:760 +msgid "Copy Part Parameter Data" +msgstr "" + +#: common/models.py:761 +msgid "Copy parameter data by default when duplicating a part" +msgstr "" + +#: common/models.py:767 +msgid "Copy Part Test Data" +msgstr "" + +#: common/models.py:768 +msgid "Copy test data by default when duplicating a part" +msgstr "" + +#: common/models.py:774 +msgid "Copy Category Parameter Templates" +msgstr "" + +#: common/models.py:775 +msgid "Copy category parameter templates when creating a part" +msgstr "" + +#: common/models.py:781 part/models.py:2593 report/models.py:183 +#: templates/js/translated/table_filters.js:38 +#: templates/js/translated/table_filters.js:444 +msgid "Template" +msgstr "" + +#: common/models.py:782 +msgid "Parts are templates by default" +msgstr "" + +#: common/models.py:788 part/models.py:959 templates/js/translated/bom.js:1315 +#: templates/js/translated/table_filters.js:168 +#: templates/js/translated/table_filters.js:460 +msgid "Assembly" +msgstr "" + +#: common/models.py:789 +msgid "Parts can be assembled from other components by default" +msgstr "" + +#: common/models.py:795 part/models.py:965 +#: templates/js/translated/table_filters.js:464 +msgid "Component" +msgstr "" + +#: common/models.py:796 +msgid "Parts can be used as sub-components by default" +msgstr "" + +#: common/models.py:802 part/models.py:976 +msgid "Purchaseable" +msgstr "" + +#: common/models.py:803 +msgid "Parts are purchaseable by default" +msgstr "" + +#: common/models.py:809 part/models.py:981 +#: templates/js/translated/table_filters.js:472 +msgid "Salable" +msgstr "" + +#: common/models.py:810 +msgid "Parts are salable by default" +msgstr "" + +#: common/models.py:816 part/models.py:971 +#: templates/js/translated/table_filters.js:46 +#: templates/js/translated/table_filters.js:100 +#: templates/js/translated/table_filters.js:476 +msgid "Trackable" +msgstr "" + +#: common/models.py:817 +msgid "Parts are trackable by default" +msgstr "" + +#: common/models.py:823 part/models.py:991 +#: part/templates/part/part_base.html:151 +#: templates/js/translated/table_filters.js:42 +msgid "Virtual" +msgstr "" + +#: common/models.py:824 +msgid "Parts are virtual by default" +msgstr "" + +#: common/models.py:830 +msgid "Show Import in Views" +msgstr "" + +#: common/models.py:831 +msgid "Display the import wizard in some part views" +msgstr "" + +#: common/models.py:837 +msgid "Show Price in Forms" +msgstr "" + +#: common/models.py:838 +msgid "Display part price in some forms" +msgstr "" + +#: common/models.py:849 +msgid "Show Price in BOM" +msgstr "" + +#: common/models.py:850 +msgid "Include pricing information in BOM tables" +msgstr "" + +#: common/models.py:861 +msgid "Show Price History" +msgstr "" + +#: common/models.py:862 +msgid "Display historical pricing for Part" +msgstr "" + +#: common/models.py:868 +msgid "Show related parts" +msgstr "" + +#: common/models.py:869 +msgid "Display related parts for a part" +msgstr "" + +#: common/models.py:875 +msgid "Create initial stock" +msgstr "" + +#: common/models.py:876 +msgid "Create initial stock on part creation" +msgstr "" + +#: common/models.py:882 +msgid "Internal Prices" +msgstr "" + +#: common/models.py:883 +msgid "Enable internal prices for parts" +msgstr "" + +#: common/models.py:889 +msgid "Internal Price as BOM-Price" +msgstr "" + +#: common/models.py:890 +msgid "Use the internal price (if set) in BOM-price calculations" +msgstr "" + +#: common/models.py:896 +msgid "Part Name Display Format" +msgstr "" + +#: common/models.py:897 +msgid "Format to display the part name" +msgstr "" + +#: common/models.py:904 +msgid "Enable Reports" +msgstr "" + +#: common/models.py:905 +msgid "Enable generation of reports" +msgstr "" + +#: common/models.py:911 templates/stats.html:25 +msgid "Debug Mode" +msgstr "" + +#: common/models.py:912 +msgid "Generate reports in debug mode (HTML output)" +msgstr "" + +#: common/models.py:918 +msgid "Page Size" +msgstr "" + +#: common/models.py:919 +msgid "Default page size for PDF reports" +msgstr "" + +#: common/models.py:929 +msgid "Test Reports" +msgstr "" + +#: common/models.py:930 +msgid "Enable generation of test reports" +msgstr "" + +#: common/models.py:936 +msgid "Stock Expiry" +msgstr "" + +#: common/models.py:937 +msgid "Enable stock expiry functionality" +msgstr "" + +#: common/models.py:943 +msgid "Sell Expired Stock" +msgstr "" + +#: common/models.py:944 +msgid "Allow sale of expired stock" +msgstr "" + +#: common/models.py:950 +msgid "Stock Stale Time" +msgstr "" + +#: common/models.py:951 +msgid "Number of days stock items are considered stale before expiring" +msgstr "" + +#: common/models.py:953 +msgid "days" +msgstr "" + +#: common/models.py:958 +msgid "Build Expired Stock" +msgstr "" + +#: common/models.py:959 +msgid "Allow building with expired stock" +msgstr "" + +#: common/models.py:965 +msgid "Stock Ownership Control" +msgstr "" + +#: common/models.py:966 +msgid "Enable ownership control over stock locations and items" +msgstr "" + +#: common/models.py:972 +msgid "Build Order Reference Prefix" +msgstr "" + +#: common/models.py:973 +msgid "Prefix value for build order reference" +msgstr "" + +#: common/models.py:978 +msgid "Build Order Reference Regex" +msgstr "" + +#: common/models.py:979 +msgid "Regular expression pattern for matching build order reference" +msgstr "" + +#: common/models.py:983 +msgid "Sales Order Reference Prefix" +msgstr "" + +#: common/models.py:984 +msgid "Prefix value for sales order reference" +msgstr "" + +#: common/models.py:989 +msgid "Purchase Order Reference Prefix" +msgstr "" + +#: common/models.py:990 +msgid "Prefix value for purchase order reference" +msgstr "" + +#: common/models.py:996 +msgid "Enable password forgot" +msgstr "" + +#: common/models.py:997 +msgid "Enable password forgot function on the login pages" +msgstr "" + +#: common/models.py:1002 +msgid "Enable registration" +msgstr "" + +#: common/models.py:1003 +msgid "Enable self-registration for users on the login pages" +msgstr "" + +#: common/models.py:1008 +msgid "Enable SSO" +msgstr "" + +#: common/models.py:1009 +msgid "Enable SSO on the login pages" +msgstr "" + +#: common/models.py:1014 +msgid "Email required" +msgstr "" + +#: common/models.py:1015 +msgid "Require user to supply mail on signup" +msgstr "" + +#: common/models.py:1020 +msgid "Auto-fill SSO users" +msgstr "" + +#: common/models.py:1021 +msgid "Automatically fill out user-details from SSO account-data" +msgstr "" + +#: common/models.py:1026 +msgid "Mail twice" +msgstr "" + +#: common/models.py:1027 +msgid "On signup ask users twice for their mail" +msgstr "" + +#: common/models.py:1032 +msgid "Password twice" +msgstr "" + +#: common/models.py:1033 +msgid "On signup ask users twice for their password" +msgstr "" + +#: common/models.py:1038 +msgid "Group on signup" +msgstr "" + +#: common/models.py:1039 +msgid "Group to which new users are assigned on registration" +msgstr "" + +#: common/models.py:1044 +msgid "Enforce MFA" +msgstr "" + +#: common/models.py:1045 +msgid "Users must use multifactor security." +msgstr "" + +#: common/models.py:1051 +msgid "Check plugins on startup" +msgstr "" + +#: common/models.py:1052 +msgid "Check that all plugins are installed on startup - enable in container enviroments" +msgstr "" + +#: common/models.py:1059 +msgid "Enable URL integration" +msgstr "" + +#: common/models.py:1060 +msgid "Enable plugins to add URL routes" +msgstr "" + +#: common/models.py:1066 +msgid "Enable navigation integration" +msgstr "" + +#: common/models.py:1067 +msgid "Enable plugins to integrate into navigation" +msgstr "" + +#: common/models.py:1073 +msgid "Enable app integration" +msgstr "" + +#: common/models.py:1074 +msgid "Enable plugins to add apps" +msgstr "" + +#: common/models.py:1080 +msgid "Enable schedule integration" +msgstr "" + +#: common/models.py:1081 +msgid "Enable plugins to run scheduled tasks" +msgstr "" + +#: common/models.py:1087 +msgid "Enable event integration" +msgstr "" + +#: common/models.py:1088 +msgid "Enable plugins to respond to internal events" +msgstr "" + +#: common/models.py:1103 common/models.py:1389 +msgid "Settings key (must be unique - case insensitive" +msgstr "" + +#: common/models.py:1134 +msgid "Show subscribed parts" +msgstr "" + +#: common/models.py:1135 +msgid "Show subscribed parts on the homepage" +msgstr "" + +#: common/models.py:1140 +msgid "Show subscribed categories" +msgstr "" + +#: common/models.py:1141 +msgid "Show subscribed part categories on the homepage" +msgstr "" + +#: common/models.py:1146 +msgid "Show latest parts" +msgstr "" + +#: common/models.py:1147 +msgid "Show latest parts on the homepage" +msgstr "" + +#: common/models.py:1152 +msgid "Recent Part Count" +msgstr "" + +#: common/models.py:1153 +msgid "Number of recent parts to display on index page" +msgstr "" + +#: common/models.py:1159 +msgid "Show unvalidated BOMs" +msgstr "" + +#: common/models.py:1160 +msgid "Show BOMs that await validation on the homepage" +msgstr "" + +#: common/models.py:1165 +msgid "Show recent stock changes" +msgstr "" + +#: common/models.py:1166 +msgid "Show recently changed stock items on the homepage" +msgstr "" + +#: common/models.py:1171 +msgid "Recent Stock Count" +msgstr "" + +#: common/models.py:1172 +msgid "Number of recent stock items to display on index page" +msgstr "" + +#: common/models.py:1177 +msgid "Show low stock" +msgstr "" + +#: common/models.py:1178 +msgid "Show low stock items on the homepage" +msgstr "" + +#: common/models.py:1183 +msgid "Show depleted stock" +msgstr "" + +#: common/models.py:1184 +msgid "Show depleted stock items on the homepage" +msgstr "" + +#: common/models.py:1189 +msgid "Show needed stock" +msgstr "" + +#: common/models.py:1190 +msgid "Show stock items needed for builds on the homepage" +msgstr "" + +#: common/models.py:1195 +msgid "Show expired stock" +msgstr "" + +#: common/models.py:1196 +msgid "Show expired stock items on the homepage" +msgstr "" + +#: common/models.py:1201 +msgid "Show stale stock" +msgstr "" + +#: common/models.py:1202 +msgid "Show stale stock items on the homepage" +msgstr "" + +#: common/models.py:1207 +msgid "Show pending builds" +msgstr "" + +#: common/models.py:1208 +msgid "Show pending builds on the homepage" +msgstr "" + +#: common/models.py:1213 +msgid "Show overdue builds" +msgstr "" + +#: common/models.py:1214 +msgid "Show overdue builds on the homepage" +msgstr "" + +#: common/models.py:1219 +msgid "Show outstanding POs" +msgstr "" + +#: common/models.py:1220 +msgid "Show outstanding POs on the homepage" +msgstr "" + +#: common/models.py:1225 +msgid "Show overdue POs" +msgstr "" + +#: common/models.py:1226 +msgid "Show overdue POs on the homepage" +msgstr "" + +#: common/models.py:1231 +msgid "Show outstanding SOs" +msgstr "" + +#: common/models.py:1232 +msgid "Show outstanding SOs on the homepage" +msgstr "" + +#: common/models.py:1237 +msgid "Show overdue SOs" +msgstr "" + +#: common/models.py:1238 +msgid "Show overdue SOs on the homepage" +msgstr "" + +#: common/models.py:1244 +msgid "Enable email notifications" +msgstr "" + +#: common/models.py:1245 +msgid "Allow sending of emails for event notifications" +msgstr "" + +#: common/models.py:1251 +msgid "Enable label printing" +msgstr "" + +#: common/models.py:1252 +msgid "Enable label printing from the web interface" +msgstr "" + +#: common/models.py:1258 +msgid "Inline label display" +msgstr "" + +#: common/models.py:1259 +msgid "Display PDF labels in the browser, instead of downloading as a file" +msgstr "" + +#: common/models.py:1265 +msgid "Inline report display" +msgstr "" + +#: common/models.py:1266 +msgid "Display PDF reports in the browser, instead of downloading as a file" +msgstr "" + +#: common/models.py:1272 +msgid "Search Parts" +msgstr "" + +#: common/models.py:1273 +msgid "Display parts in search preview window" +msgstr "" + +#: common/models.py:1279 +msgid "Search Categories" +msgstr "" + +#: common/models.py:1280 +msgid "Display part categories in search preview window" +msgstr "" + +#: common/models.py:1286 +msgid "Search Stock" +msgstr "" + +#: common/models.py:1287 +msgid "Display stock items in search preview window" +msgstr "" + +#: common/models.py:1293 +msgid "Search Locations" +msgstr "" + +#: common/models.py:1294 +msgid "Display stock locations in search preview window" +msgstr "" + +#: common/models.py:1300 +msgid "Search Companies" +msgstr "" + +#: common/models.py:1301 +msgid "Display companies in search preview window" +msgstr "" + +#: common/models.py:1307 +msgid "Search Purchase Orders" +msgstr "" + +#: common/models.py:1308 +msgid "Display purchase orders in search preview window" +msgstr "" + +#: common/models.py:1314 +msgid "Search Sales Orders" +msgstr "" + +#: common/models.py:1315 +msgid "Display sales orders in search preview window" +msgstr "" + +#: common/models.py:1321 +msgid "Search Preview Results" +msgstr "" + +#: common/models.py:1322 +msgid "Number of results to show in each section of the search preview window" +msgstr "" + +#: common/models.py:1328 +msgid "Hide Inactive Parts" +msgstr "" + +#: common/models.py:1329 +msgid "Hide inactive parts in search preview window" +msgstr "" + +#: common/models.py:1335 +msgid "Show Quantity in Forms" +msgstr "" + +#: common/models.py:1336 +msgid "Display available part quantity in some forms" +msgstr "" + +#: common/models.py:1342 +msgid "Escape Key Closes Forms" +msgstr "" + +#: common/models.py:1343 +msgid "Use the escape key to close modal forms" +msgstr "" + +#: common/models.py:1349 +msgid "Fixed Navbar" +msgstr "" + +#: common/models.py:1350 +msgid "InvenTree navbar position is fixed to the top of the screen" +msgstr "" + +#: common/models.py:1356 +msgid "Date Format" +msgstr "" + +#: common/models.py:1357 +msgid "Preferred format for displaying dates" +msgstr "" + +#: common/models.py:1371 part/templates/part/detail.html:39 +msgid "Part Scheduling" +msgstr "" + +#: common/models.py:1372 +msgid "Display part scheduling information" +msgstr "" + +#: common/models.py:1430 company/forms.py:43 +msgid "Price break quantity" +msgstr "" + +#: common/models.py:1437 company/serializers.py:264 +#: company/templates/company/supplier_part.html:256 +#: templates/js/translated/part.js:980 templates/js/translated/part.js:1966 +msgid "Price" +msgstr "" + +#: common/models.py:1438 +msgid "Unit price at specified quantity" +msgstr "" + +#: common/models.py:1595 common/models.py:1734 +msgid "Endpoint" +msgstr "" + +#: common/models.py:1596 +msgid "Endpoint at which this webhook is received" +msgstr "" + +#: common/models.py:1605 +msgid "Name for this webhook" +msgstr "" + +#: common/models.py:1610 part/models.py:986 plugin/models.py:46 +#: templates/js/translated/table_filters.js:34 +#: templates/js/translated/table_filters.js:96 +#: templates/js/translated/table_filters.js:308 +#: templates/js/translated/table_filters.js:439 +msgid "Active" +msgstr "" + +#: common/models.py:1611 +msgid "Is this webhook active" +msgstr "" + +#: common/models.py:1625 +msgid "Token" +msgstr "" + +#: common/models.py:1626 +msgid "Token for access" +msgstr "" + +#: common/models.py:1633 +msgid "Secret" +msgstr "" + +#: common/models.py:1634 +msgid "Shared secret for HMAC" +msgstr "" + +#: common/models.py:1701 +msgid "Message ID" +msgstr "" + +#: common/models.py:1702 +msgid "Unique identifier for this message" +msgstr "" + +#: common/models.py:1710 +msgid "Host" +msgstr "" + +#: common/models.py:1711 +msgid "Host from which this message was received" +msgstr "" + +#: common/models.py:1718 +msgid "Header" +msgstr "" + +#: common/models.py:1719 +msgid "Header of this message" +msgstr "" + +#: common/models.py:1725 +msgid "Body" +msgstr "" + +#: common/models.py:1726 +msgid "Body of this message" +msgstr "" + +#: common/models.py:1735 +msgid "Endpoint on which this message was received" +msgstr "" + +#: common/models.py:1740 +msgid "Worked on" +msgstr "" + +#: common/models.py:1741 +msgid "Was the work on this message finished?" +msgstr "" + +#: common/views.py:93 order/templates/order/purchase_order_detail.html:23 +#: order/views.py:243 part/views.py:208 +#: templates/patterns/wizard/upload.html:37 +msgid "Upload File" +msgstr "" + +#: common/views.py:94 order/views.py:244 +#: part/templates/part/import_wizard/ajax_match_fields.html:45 +#: part/views.py:209 templates/patterns/wizard/match_fields.html:51 +msgid "Match Fields" +msgstr "" + +#: common/views.py:95 +msgid "Match Items" +msgstr "" + +#: common/views.py:440 +msgid "Fields matching failed" +msgstr "" + +#: common/views.py:495 +msgid "Parts imported" +msgstr "" + +#: common/views.py:517 order/templates/order/order_wizard/match_parts.html:19 +#: part/templates/part/import_wizard/match_references.html:19 +#: templates/patterns/wizard/match_fields.html:26 +#: templates/patterns/wizard/upload.html:35 +msgid "Previous Step" +msgstr "" + +#: company/forms.py:24 part/forms.py:46 +#: templates/InvenTree/settings/mixins/urls.html:14 +msgid "URL" +msgstr "" + +#: company/forms.py:25 part/forms.py:47 +msgid "Image URL" +msgstr "" + +#: company/models.py:105 +msgid "Company description" +msgstr "" + +#: company/models.py:106 +msgid "Description of the company" +msgstr "" + +#: company/models.py:112 company/templates/company/company_base.html:97 +#: templates/InvenTree/settings/plugin_settings.html:55 +#: templates/js/translated/company.js:349 +msgid "Website" +msgstr "" + +#: company/models.py:113 +msgid "Company website URL" +msgstr "" + +#: company/models.py:117 company/templates/company/company_base.html:115 +msgid "Address" +msgstr "" + +#: company/models.py:118 +msgid "Company address" +msgstr "" + +#: company/models.py:121 +msgid "Phone number" +msgstr "" + +#: company/models.py:122 +msgid "Contact phone number" +msgstr "" + +#: company/models.py:125 company/templates/company/company_base.html:129 +#: templates/InvenTree/settings/user.html:48 +msgid "Email" +msgstr "" + +#: company/models.py:125 +msgid "Contact email address" +msgstr "" + +#: company/models.py:128 company/templates/company/company_base.html:136 +msgid "Contact" +msgstr "" + +#: company/models.py:129 +msgid "Point of contact" +msgstr "" + +#: company/models.py:131 +msgid "Link to external company information" +msgstr "" + +#: company/models.py:139 part/models.py:878 +msgid "Image" +msgstr "" + +#: company/models.py:144 +msgid "is customer" +msgstr "" + +#: company/models.py:144 +msgid "Do you sell items to this company?" +msgstr "" + +#: company/models.py:146 +msgid "is supplier" +msgstr "" + +#: company/models.py:146 +msgid "Do you purchase items from this company?" +msgstr "" + +#: company/models.py:148 +msgid "is manufacturer" +msgstr "" + +#: company/models.py:148 +msgid "Does this company manufacture parts?" +msgstr "" + +#: company/models.py:152 company/serializers.py:270 +#: company/templates/company/company_base.html:103 stock/serializers.py:179 +msgid "Currency" +msgstr "" + +#: company/models.py:155 +msgid "Default currency used for this company" +msgstr "" + +#: company/models.py:320 company/models.py:535 stock/models.py:581 +#: stock/templates/stock/item_base.html:142 templates/js/translated/bom.js:541 +msgid "Base Part" +msgstr "" + +#: company/models.py:324 company/models.py:539 +msgid "Select part" +msgstr "" + +#: company/models.py:335 company/templates/company/company_base.html:73 +#: company/templates/company/manufacturer_part.html:91 +#: company/templates/company/supplier_part.html:97 +#: stock/templates/stock/item_base.html:364 +#: templates/js/translated/company.js:333 +#: templates/js/translated/company.js:517 +#: templates/js/translated/company.js:800 templates/js/translated/part.js:235 +#: templates/js/translated/table_filters.js:411 +msgid "Manufacturer" +msgstr "" + +#: company/models.py:336 templates/js/translated/part.js:236 +msgid "Select manufacturer" +msgstr "" + +#: company/models.py:342 company/templates/company/manufacturer_part.html:96 +#: company/templates/company/supplier_part.html:105 +#: templates/js/translated/company.js:533 +#: templates/js/translated/company.js:818 templates/js/translated/order.js:1211 +#: templates/js/translated/part.js:246 templates/js/translated/part.js:938 +msgid "MPN" +msgstr "" + +#: company/models.py:343 templates/js/translated/part.js:247 +msgid "Manufacturer Part Number" +msgstr "" + +#: company/models.py:349 +msgid "URL for external manufacturer part link" +msgstr "" + +#: company/models.py:355 +msgid "Manufacturer part description" +msgstr "" + +#: company/models.py:409 company/models.py:558 +#: company/templates/company/manufacturer_part.html:6 +#: company/templates/company/manufacturer_part.html:23 +#: stock/templates/stock/item_base.html:374 +msgid "Manufacturer Part" +msgstr "" + +#: company/models.py:416 +msgid "Parameter name" +msgstr "" + +#: company/models.py:422 +#: report/templates/report/inventree_test_report_base.html:95 +#: stock/models.py:2164 templates/js/translated/company.js:647 +#: templates/js/translated/part.js:758 templates/js/translated/stock.js:1303 +msgid "Value" +msgstr "" + +#: company/models.py:423 +msgid "Parameter value" +msgstr "" + +#: company/models.py:429 part/models.py:953 part/models.py:2561 +#: part/templates/part/part_base.html:306 +#: templates/InvenTree/settings/settings.html:325 +#: templates/js/translated/company.js:653 templates/js/translated/part.js:764 +msgid "Units" +msgstr "" + +#: company/models.py:430 +msgid "Parameter units" +msgstr "" + +#: company/models.py:502 +msgid "Linked manufacturer part must reference the same base part" +msgstr "" + +#: company/models.py:545 company/templates/company/company_base.html:78 +#: company/templates/company/supplier_part.html:87 order/models.py:227 +#: order/templates/order/order_base.html:112 +#: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:237 +#: part/bom.py:265 stock/templates/stock/item_base.html:381 +#: templates/js/translated/company.js:337 +#: templates/js/translated/company.js:774 templates/js/translated/order.js:958 +#: templates/js/translated/part.js:216 templates/js/translated/part.js:906 +#: templates/js/translated/table_filters.js:415 +msgid "Supplier" +msgstr "" + +#: company/models.py:546 templates/js/translated/part.js:217 +msgid "Select supplier" +msgstr "" + +#: company/models.py:551 company/templates/company/supplier_part.html:91 +#: part/bom.py:238 part/bom.py:266 templates/js/translated/order.js:1198 +#: templates/js/translated/part.js:227 templates/js/translated/part.js:924 +msgid "SKU" +msgstr "" + +#: company/models.py:552 templates/js/translated/part.js:228 +msgid "Supplier stock keeping unit" +msgstr "" + +#: company/models.py:559 +msgid "Select manufacturer part" +msgstr "" + +#: company/models.py:565 +msgid "URL for external supplier part link" +msgstr "" + +#: company/models.py:571 +msgid "Supplier part description" +msgstr "" + +#: company/models.py:576 company/templates/company/supplier_part.html:119 +#: part/models.py:2786 part/templates/part/upload_bom.html:59 +#: report/templates/report/inventree_po_report.html:92 +#: report/templates/report/inventree_so_report.html:93 stock/serializers.py:409 +msgid "Note" +msgstr "" + +#: company/models.py:580 part/models.py:1871 +msgid "base cost" +msgstr "" + +#: company/models.py:580 part/models.py:1871 +msgid "Minimum charge (e.g. stocking fee)" +msgstr "" + +#: company/models.py:582 company/templates/company/supplier_part.html:112 +#: stock/models.py:605 stock/templates/stock/item_base.html:322 +#: templates/js/translated/company.js:850 templates/js/translated/stock.js:1917 +msgid "Packaging" +msgstr "" + +#: company/models.py:582 +msgid "Part packaging" +msgstr "" + +#: company/models.py:584 part/models.py:1873 +msgid "multiple" +msgstr "" + +#: company/models.py:584 +msgid "Order multiple" +msgstr "" + +#: company/models.py:708 +msgid "last updated" +msgstr "" + +#: company/serializers.py:70 +msgid "Default currency used for this supplier" +msgstr "" + +#: company/serializers.py:71 +msgid "Currency Code" +msgstr "" + +#: company/templates/company/company_base.html:8 +#: company/templates/company/company_base.html:12 +#: templates/InvenTree/search.html:176 templates/js/translated/company.js:322 +msgid "Company" +msgstr "" + +#: company/templates/company/company_base.html:22 +#: templates/js/translated/order.js:279 +msgid "Create Purchase Order" +msgstr "" + +#: company/templates/company/company_base.html:26 +msgid "Company actions" +msgstr "" + +#: company/templates/company/company_base.html:31 +msgid "Edit company information" +msgstr "" + +#: company/templates/company/company_base.html:32 +#: templates/js/translated/company.js:265 +msgid "Edit Company" +msgstr "" + +#: company/templates/company/company_base.html:36 +msgid "Delete company" +msgstr "" + +#: company/templates/company/company_base.html:37 +#: company/templates/company/company_base.html:159 +msgid "Delete Company" +msgstr "" + +#: company/templates/company/company_base.html:53 +#: part/templates/part/part_thumb.html:12 +msgid "Upload new image" +msgstr "" + +#: company/templates/company/company_base.html:56 +#: part/templates/part/part_thumb.html:14 +msgid "Download image from URL" +msgstr "" + +#: company/templates/company/company_base.html:83 order/models.py:574 +#: order/templates/order/sales_order_base.html:115 stock/models.py:624 +#: stock/models.py:625 stock/serializers.py:683 +#: stock/templates/stock/item_base.html:274 +#: templates/js/translated/company.js:329 templates/js/translated/order.js:1436 +#: templates/js/translated/stock.js:2435 +#: templates/js/translated/table_filters.js:419 +msgid "Customer" +msgstr "" + +#: company/templates/company/company_base.html:108 +msgid "Uses default currency" +msgstr "" + +#: company/templates/company/company_base.html:122 +msgid "Phone" +msgstr "" + +#: company/templates/company/company_base.html:205 +#: part/templates/part/part_base.html:491 +msgid "Upload Image" +msgstr "" + +#: company/templates/company/detail.html:14 +#: company/templates/company/manufacturer_part_sidebar.html:7 +#: templates/InvenTree/search.html:118 +msgid "Supplier Parts" +msgstr "" + +#: company/templates/company/detail.html:18 +#: order/templates/order/order_wizard/select_parts.html:44 +msgid "Create new supplier part" +msgstr "" + +#: company/templates/company/detail.html:19 +#: company/templates/company/manufacturer_part.html:118 +#: part/templates/part/detail.html:353 +msgid "New Supplier Part" +msgstr "" + +#: company/templates/company/detail.html:31 +#: company/templates/company/detail.html:78 +#: company/templates/company/manufacturer_part.html:127 +#: company/templates/company/manufacturer_part.html:156 +#: part/templates/part/category.html:168 part/templates/part/detail.html:362 +#: part/templates/part/detail.html:391 +msgid "Options" +msgstr "" + +#: company/templates/company/detail.html:36 +#: company/templates/company/detail.html:83 +#: part/templates/part/category.html:174 +msgid "Order parts" +msgstr "" + +#: company/templates/company/detail.html:41 +#: company/templates/company/detail.html:88 +msgid "Delete parts" +msgstr "" + +#: company/templates/company/detail.html:42 +#: company/templates/company/detail.html:89 +msgid "Delete Parts" +msgstr "" + +#: company/templates/company/detail.html:61 templates/InvenTree/search.html:103 +msgid "Manufacturer Parts" +msgstr "" + +#: company/templates/company/detail.html:65 +msgid "Create new manufacturer part" +msgstr "" + +#: company/templates/company/detail.html:66 part/templates/part/detail.html:381 +msgid "New Manufacturer Part" +msgstr "" + +#: company/templates/company/detail.html:106 +msgid "Supplier Stock" +msgstr "" + +#: company/templates/company/detail.html:116 +#: company/templates/company/sidebar.html:12 +#: company/templates/company/supplier_part_sidebar.html:7 +#: order/templates/order/order_base.html:13 +#: order/templates/order/purchase_orders.html:8 +#: order/templates/order/purchase_orders.html:12 +#: part/templates/part/detail.html:77 part/templates/part/part_sidebar.html:38 +#: templates/InvenTree/index.html:252 templates/InvenTree/search.html:197 +#: templates/InvenTree/settings/sidebar.html:47 +#: templates/js/translated/search.js:173 templates/navbar.html:47 +#: users/models.py:45 +msgid "Purchase Orders" +msgstr "" + +#: company/templates/company/detail.html:120 +#: order/templates/order/purchase_orders.html:17 +msgid "Create new purchase order" +msgstr "" + +#: company/templates/company/detail.html:121 +#: order/templates/order/purchase_orders.html:18 +msgid "New Purchase Order" +msgstr "" + +#: company/templates/company/detail.html:142 +#: company/templates/company/sidebar.html:20 +#: order/templates/order/sales_order_base.html:13 +#: order/templates/order/sales_orders.html:8 +#: order/templates/order/sales_orders.html:15 +#: part/templates/part/detail.html:100 part/templates/part/part_sidebar.html:42 +#: templates/InvenTree/index.html:283 templates/InvenTree/search.html:217 +#: templates/InvenTree/settings/sidebar.html:49 +#: templates/js/translated/search.js:190 templates/navbar.html:58 +#: users/models.py:46 +msgid "Sales Orders" +msgstr "" + +#: company/templates/company/detail.html:146 +#: order/templates/order/sales_orders.html:20 +msgid "Create new sales order" +msgstr "" + +#: company/templates/company/detail.html:147 +#: order/templates/order/sales_orders.html:21 +msgid "New Sales Order" +msgstr "" + +#: company/templates/company/detail.html:167 +#: templates/js/translated/build.js:1295 +msgid "Assigned Stock" +msgstr "" + +#: company/templates/company/detail.html:184 +msgid "Company Notes" +msgstr "" + +#: company/templates/company/detail.html:375 +#: company/templates/company/manufacturer_part.html:215 +#: part/templates/part/detail.html:452 +msgid "Delete Supplier Parts?" +msgstr "" + +#: company/templates/company/detail.html:376 +#: company/templates/company/manufacturer_part.html:216 +#: part/templates/part/detail.html:453 +msgid "All selected supplier parts will be deleted" +msgstr "" + +#: company/templates/company/index.html:8 +msgid "Supplier List" +msgstr "" + +#: company/templates/company/manufacturer_part.html:14 company/views.py:55 +#: part/templates/part/prices.html:167 templates/InvenTree/search.html:178 +#: templates/navbar.html:46 +msgid "Manufacturers" +msgstr "" + +#: company/templates/company/manufacturer_part.html:35 +#: company/templates/company/supplier_part.html:34 +#: company/templates/company/supplier_part.html:159 +#: part/templates/part/detail.html:80 part/templates/part/part_base.html:80 +msgid "Order part" +msgstr "" + +#: company/templates/company/manufacturer_part.html:40 +#: templates/js/translated/company.js:565 +msgid "Edit manufacturer part" +msgstr "" + +#: company/templates/company/manufacturer_part.html:44 +#: templates/js/translated/company.js:566 +msgid "Delete manufacturer part" +msgstr "" + +#: company/templates/company/manufacturer_part.html:66 +#: company/templates/company/supplier_part.html:63 +msgid "Internal Part" +msgstr "" + +#: company/templates/company/manufacturer_part.html:114 +#: company/templates/company/supplier_part.html:15 company/views.py:49 +#: part/templates/part/part_sidebar.html:36 part/templates/part/prices.html:163 +#: templates/InvenTree/search.html:188 templates/navbar.html:45 +msgid "Suppliers" +msgstr "" + +#: company/templates/company/manufacturer_part.html:129 +#: part/templates/part/detail.html:364 +msgid "Delete supplier parts" +msgstr "" + +#: company/templates/company/manufacturer_part.html:129 +#: company/templates/company/manufacturer_part.html:158 +#: company/templates/company/manufacturer_part.html:254 +#: part/templates/part/detail.html:364 part/templates/part/detail.html:393 +#: templates/js/translated/company.js:426 templates/js/translated/helpers.js:32 +#: users/models.py:218 +msgid "Delete" +msgstr "" + +#: company/templates/company/manufacturer_part.html:143 +#: company/templates/company/manufacturer_part_sidebar.html:5 +#: part/templates/part/category_sidebar.html:19 +#: part/templates/part/detail.html:180 part/templates/part/part_sidebar.html:9 +msgid "Parameters" +msgstr "" + +#: company/templates/company/manufacturer_part.html:147 +#: part/templates/part/detail.html:185 +#: templates/InvenTree/settings/category.html:12 +#: templates/InvenTree/settings/part.html:66 +msgid "New Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part.html:158 +msgid "Delete parameters" +msgstr "" + +#: company/templates/company/manufacturer_part.html:191 +#: part/templates/part/detail.html:865 +msgid "Add Parameter" +msgstr "" + +#: company/templates/company/manufacturer_part.html:239 +msgid "Selected parameters will be deleted" +msgstr "" + +#: company/templates/company/manufacturer_part.html:251 +msgid "Delete Parameters" +msgstr "" + +#: company/templates/company/sidebar.html:6 +msgid "Manufactured Parts" +msgstr "" + +#: company/templates/company/sidebar.html:10 +msgid "Supplied Parts" +msgstr "" + +#: company/templates/company/sidebar.html:16 +msgid "Supplied Stock Items" +msgstr "" + +#: company/templates/company/sidebar.html:22 +msgid "Assigned Stock Items" +msgstr "" + +#: company/templates/company/supplier_part.html:7 +#: company/templates/company/supplier_part.html:24 stock/models.py:589 +#: stock/templates/stock/item_base.html:386 +#: templates/js/translated/company.js:790 templates/js/translated/stock.js:1874 +msgid "Supplier Part" +msgstr "" + +#: company/templates/company/supplier_part.html:38 +#: templates/js/translated/company.js:863 +msgid "Edit supplier part" +msgstr "" + +#: company/templates/company/supplier_part.html:42 +#: templates/js/translated/company.js:864 +msgid "Delete supplier part" +msgstr "" + +#: company/templates/company/supplier_part.html:138 +#: company/templates/company/supplier_part_navbar.html:12 +msgid "Supplier Part Stock" +msgstr "" + +#: company/templates/company/supplier_part.html:141 +#: part/templates/part/detail.html:23 stock/templates/stock/location.html:167 +msgid "Create new stock item" +msgstr "" + +#: company/templates/company/supplier_part.html:142 +#: part/templates/part/detail.html:24 stock/templates/stock/location.html:168 +#: templates/js/translated/stock.js:379 +msgid "New Stock Item" +msgstr "" + +#: company/templates/company/supplier_part.html:155 +#: company/templates/company/supplier_part_navbar.html:19 +msgid "Supplier Part Orders" +msgstr "" + +#: company/templates/company/supplier_part.html:160 +#: part/templates/part/detail.html:81 +msgid "Order Part" +msgstr "" + +#: company/templates/company/supplier_part.html:179 +#: part/templates/part/prices.html:7 +msgid "Pricing Information" +msgstr "" + +#: company/templates/company/supplier_part.html:184 +#: company/templates/company/supplier_part.html:298 +#: part/templates/part/prices.html:271 part/views.py:1238 +msgid "Add Price Break" +msgstr "" + +#: company/templates/company/supplier_part.html:210 +msgid "No price break information found" +msgstr "" + +#: company/templates/company/supplier_part.html:224 part/views.py:1300 +msgid "Delete Price Break" +msgstr "" + +#: company/templates/company/supplier_part.html:238 part/views.py:1286 +msgid "Edit Price Break" +msgstr "" + +#: company/templates/company/supplier_part.html:263 +msgid "Edit price break" +msgstr "" + +#: company/templates/company/supplier_part.html:264 +msgid "Delete price break" +msgstr "" + +#: company/templates/company/supplier_part.html:273 +msgid "Last updated" +msgstr "" + +#: company/templates/company/supplier_part_navbar.html:15 +#: part/templates/part/part_sidebar.html:15 +#: stock/templates/stock/loc_link.html:3 stock/templates/stock/location.html:18 +#: stock/templates/stock/stock_app_base.html:10 +#: templates/InvenTree/search.html:150 +#: templates/InvenTree/settings/sidebar.html:43 +#: templates/js/translated/bom.js:553 templates/js/translated/part.js:673 +#: templates/js/translated/part.js:1208 templates/js/translated/part.js:1369 +#: templates/js/translated/stock.js:903 templates/js/translated/stock.js:1696 +#: templates/navbar.html:28 +msgid "Stock" +msgstr "" + +#: company/templates/company/supplier_part_navbar.html:22 +msgid "Orders" +msgstr "" + +#: company/templates/company/supplier_part_navbar.html:26 +#: company/templates/company/supplier_part_sidebar.html:9 +msgid "Supplier Part Pricing" +msgstr "" + +#: company/templates/company/supplier_part_navbar.html:29 +#: part/templates/part/part_sidebar.html:32 +msgid "Pricing" +msgstr "" + +#: company/templates/company/supplier_part_sidebar.html:5 +#: part/templates/part/category.html:192 +#: part/templates/part/category_sidebar.html:17 +#: stock/templates/stock/location.html:138 +#: stock/templates/stock/location.html:152 +#: stock/templates/stock/location.html:164 +#: stock/templates/stock/location_sidebar.html:7 +#: templates/InvenTree/search.html:152 templates/js/translated/search.js:127 +#: templates/js/translated/stock.js:2311 templates/stats.html:105 +#: templates/stats.html:114 users/models.py:43 +msgid "Stock Items" +msgstr "" + +#: company/views.py:50 +msgid "New Supplier" +msgstr "" + +#: company/views.py:56 +msgid "New Manufacturer" +msgstr "" + +#: company/views.py:61 templates/InvenTree/search.html:208 +#: templates/navbar.html:57 +msgid "Customers" +msgstr "" + +#: company/views.py:62 +msgid "New Customer" +msgstr "" + +#: company/views.py:69 templates/js/translated/search.js:159 +msgid "Companies" +msgstr "" + +#: company/views.py:70 +msgid "New Company" +msgstr "" + +#: company/views.py:129 part/views.py:589 +msgid "Download Image" +msgstr "" + +#: company/views.py:158 part/views.py:621 +msgid "Image size exceeds maximum allowable size for download" +msgstr "" + +#: company/views.py:165 part/views.py:628 +#, python-brace-format +msgid "Invalid response: {code}" +msgstr "" + +#: company/views.py:174 part/views.py:637 +msgid "Supplied URL is not a valid image file" +msgstr "" + +#: label/api.py:97 report/api.py:203 +msgid "No valid objects provided to template" +msgstr "" + +#: label/models.py:113 +msgid "Label name" +msgstr "" + +#: label/models.py:120 +msgid "Label description" +msgstr "" + +#: label/models.py:127 +msgid "Label" +msgstr "" + +#: label/models.py:128 +msgid "Label template file" +msgstr "" + +#: label/models.py:134 report/models.py:294 +msgid "Enabled" +msgstr "" + +#: label/models.py:135 +msgid "Label template is enabled" +msgstr "" + +#: label/models.py:140 +msgid "Width [mm]" +msgstr "" + +#: label/models.py:141 +msgid "Label width, specified in mm" +msgstr "" + +#: label/models.py:147 +msgid "Height [mm]" +msgstr "" + +#: label/models.py:148 +msgid "Label height, specified in mm" +msgstr "" + +#: label/models.py:154 report/models.py:287 +msgid "Filename Pattern" +msgstr "" + +#: label/models.py:155 +msgid "Pattern for generating label filenames" +msgstr "" + +#: label/models.py:258 +msgid "Query filters (comma-separated list of key=value pairs)," +msgstr "" + +#: label/models.py:259 label/models.py:319 label/models.py:366 +#: report/models.py:318 report/models.py:455 report/models.py:493 +msgid "Filters" +msgstr "" + +#: label/models.py:318 +msgid "Query filters (comma-separated list of key=value pairs" +msgstr "" + +#: label/models.py:365 +msgid "Part query filters (comma-separated value of key=value pairs)" +msgstr "" + +#: order/forms.py:24 order/templates/order/order_base.html:52 +msgid "Place order" +msgstr "" + +#: order/forms.py:35 order/templates/order/order_base.html:60 +msgid "Mark order as complete" +msgstr "" + +#: order/forms.py:46 order/forms.py:57 order/templates/order/order_base.html:47 +#: order/templates/order/sales_order_base.html:60 +msgid "Cancel order" +msgstr "" + +#: order/models.py:125 +msgid "Order description" +msgstr "" + +#: order/models.py:127 +msgid "Link to external page" +msgstr "" + +#: order/models.py:135 +msgid "Created By" +msgstr "" + +#: order/models.py:142 +msgid "User or group responsible for this order" +msgstr "" + +#: order/models.py:147 +msgid "Order notes" +msgstr "" + +#: order/models.py:214 order/models.py:564 +msgid "Order reference" +msgstr "" + +#: order/models.py:219 order/models.py:579 +msgid "Purchase order status" +msgstr "" + +#: order/models.py:228 +msgid "Company from which the items are being ordered" +msgstr "" + +#: order/models.py:231 order/templates/order/order_base.html:118 +#: templates/js/translated/order.js:967 +msgid "Supplier Reference" +msgstr "" + +#: order/models.py:231 +msgid "Supplier order reference code" +msgstr "" + +#: order/models.py:238 +msgid "received by" +msgstr "" + +#: order/models.py:243 +msgid "Issue Date" +msgstr "" + +#: order/models.py:244 +msgid "Date order was issued" +msgstr "" + +#: order/models.py:249 +msgid "Target Delivery Date" +msgstr "" + +#: order/models.py:250 +msgid "Expected date for order delivery. Order will be overdue after this date." +msgstr "" + +#: order/models.py:256 +msgid "Date order was completed" +msgstr "" + +#: order/models.py:285 +msgid "Part supplier must match PO supplier" +msgstr "" + +#: order/models.py:430 +msgid "Quantity must be a positive number" +msgstr "" + +#: order/models.py:575 +msgid "Company to which the items are being sold" +msgstr "" + +#: order/models.py:581 +msgid "Customer Reference " +msgstr "" + +#: order/models.py:581 +msgid "Customer order reference code" +msgstr "" + +#: order/models.py:586 +msgid "Target date for order completion. Order will be overdue after this date." +msgstr "" + +#: order/models.py:589 order/models.py:1084 +#: templates/js/translated/order.js:1483 templates/js/translated/order.js:1634 +msgid "Shipment Date" +msgstr "" + +#: order/models.py:596 +msgid "shipped by" +msgstr "" + +#: order/models.py:662 +msgid "Order cannot be completed as no parts have been assigned" +msgstr "" + +#: order/models.py:666 +msgid "Only a pending order can be marked as complete" +msgstr "" + +#: order/models.py:669 +msgid "Order cannot be completed as there are incomplete shipments" +msgstr "" + +#: order/models.py:672 +msgid "Order cannot be completed as there are incomplete line items" +msgstr "" + +#: order/models.py:837 +msgid "Item quantity" +msgstr "" + +#: order/models.py:843 +msgid "Line item reference" +msgstr "" + +#: order/models.py:845 +msgid "Line item notes" +msgstr "" + +#: order/models.py:850 +msgid "Target shipping date for this line item" +msgstr "" + +#: order/models.py:878 +msgid "Supplier part must match supplier" +msgstr "" + +#: order/models.py:891 order/models.py:982 order/models.py:1078 +#: templates/js/translated/order.js:2025 +msgid "Order" +msgstr "" + +#: order/models.py:892 order/templates/order/order_base.html:9 +#: order/templates/order/order_base.html:18 +#: report/templates/report/inventree_po_report.html:76 +#: stock/templates/stock/item_base.html:336 +#: templates/js/translated/order.js:936 templates/js/translated/part.js:881 +#: templates/js/translated/stock.js:1851 templates/js/translated/stock.js:2416 +msgid "Purchase Order" +msgstr "" + +#: order/models.py:913 +msgid "Supplier part" +msgstr "" + +#: order/models.py:920 order/templates/order/order_base.html:163 +#: templates/js/translated/order.js:714 templates/js/translated/order.js:1313 +#: templates/js/translated/part.js:975 templates/js/translated/part.js:1002 +#: templates/js/translated/table_filters.js:330 +msgid "Received" +msgstr "" + +#: order/models.py:921 +msgid "Number of items received" +msgstr "" + +#: order/models.py:928 part/templates/part/prices.html:176 stock/models.py:718 +#: stock/serializers.py:170 stock/templates/stock/item_base.html:343 +#: templates/js/translated/stock.js:1905 +msgid "Purchase Price" +msgstr "" + +#: order/models.py:929 +msgid "Unit purchase price" +msgstr "" + +#: order/models.py:937 +msgid "Where does the Purchaser want this item to be stored?" +msgstr "" + +#: order/models.py:992 part/templates/part/part_pricing.html:112 +#: part/templates/part/prices.html:116 part/templates/part/prices.html:284 +msgid "Sale Price" +msgstr "" + +#: order/models.py:993 +msgid "Unit sale price" +msgstr "" + +#: order/models.py:998 +msgid "Shipped quantity" +msgstr "" + +#: order/models.py:1085 +msgid "Date of shipment" +msgstr "" + +#: order/models.py:1092 +msgid "Checked By" +msgstr "" + +#: order/models.py:1093 +msgid "User who checked this shipment" +msgstr "" + +#: order/models.py:1101 +msgid "Shipment number" +msgstr "" + +#: order/models.py:1108 +msgid "Shipment notes" +msgstr "" + +#: order/models.py:1115 +msgid "Tracking Number" +msgstr "" + +#: order/models.py:1116 +msgid "Shipment tracking information" +msgstr "" + +#: order/models.py:1126 +msgid "Shipment has already been sent" +msgstr "" + +#: order/models.py:1129 +msgid "Shipment has no allocated stock items" +msgstr "" + +#: order/models.py:1207 order/models.py:1209 +msgid "Stock item has not been assigned" +msgstr "" + +#: order/models.py:1213 +msgid "Cannot allocate stock item to a line with a different part" +msgstr "" + +#: order/models.py:1215 +msgid "Cannot allocate stock to a line without a part" +msgstr "" + +#: order/models.py:1218 +msgid "Allocation quantity cannot exceed stock quantity" +msgstr "" + +#: order/models.py:1222 +msgid "StockItem is over-allocated" +msgstr "" + +#: order/models.py:1228 order/serializers.py:827 +msgid "Quantity must be 1 for serialized stock item" +msgstr "" + +#: order/models.py:1231 +msgid "Sales order does not match shipment" +msgstr "" + +#: order/models.py:1232 +msgid "Shipment does not match sales order" +msgstr "" + +#: order/models.py:1240 +msgid "Line" +msgstr "" + +#: order/models.py:1248 order/serializers.py:918 order/serializers.py:1046 +#: templates/js/translated/model_renderers.js:304 +msgid "Shipment" +msgstr "" + +#: order/models.py:1249 +msgid "Sales order shipment reference" +msgstr "" + +#: order/models.py:1261 templates/InvenTree/notifications/notifications.html:70 +msgid "Item" +msgstr "" + +#: order/models.py:1262 +msgid "Select stock item to allocate" +msgstr "" + +#: order/models.py:1265 +msgid "Enter stock allocation quantity" +msgstr "" + +#: order/serializers.py:187 +msgid "Purchase price currency" +msgstr "" + +#: order/serializers.py:238 order/serializers.py:883 +msgid "Line Item" +msgstr "" + +#: order/serializers.py:244 +msgid "Line item does not match purchase order" +msgstr "" + +#: order/serializers.py:254 order/serializers.py:359 +msgid "Select destination location for received items" +msgstr "" + +#: order/serializers.py:273 templates/js/translated/order.js:574 +msgid "Enter batch code for incoming stock items" +msgstr "" + +#: order/serializers.py:281 templates/js/translated/order.js:585 +msgid "Enter serial numbers for incoming stock items" +msgstr "" + +#: order/serializers.py:294 +msgid "Barcode Hash" +msgstr "" + +#: order/serializers.py:295 +msgid "Unique identifier field" +msgstr "" + +#: order/serializers.py:312 +msgid "Barcode is already in use" +msgstr "" + +#: order/serializers.py:331 +msgid "An integer quantity must be provided for trackable parts" +msgstr "" + +#: order/serializers.py:371 +msgid "Line items must be provided" +msgstr "" + +#: order/serializers.py:388 +msgid "Destination location must be specified" +msgstr "" + +#: order/serializers.py:399 +msgid "Supplied barcode values must be unique" +msgstr "" + +#: order/serializers.py:672 +msgid "Sale price currency" +msgstr "" + +#: order/serializers.py:742 +msgid "No shipment details provided" +msgstr "" + +#: order/serializers.py:792 order/serializers.py:895 +msgid "Line item is not associated with this order" +msgstr "" + +#: order/serializers.py:814 +msgid "Quantity must be positive" +msgstr "" + +#: order/serializers.py:908 +msgid "Enter serial numbers to allocate" +msgstr "" + +#: order/serializers.py:932 order/serializers.py:1057 +msgid "Shipment has already been shipped" +msgstr "" + +#: order/serializers.py:935 order/serializers.py:1060 +msgid "Shipment is not associated with this order" +msgstr "" + +#: order/serializers.py:987 +msgid "No match found for the following serial numbers" +msgstr "" + +#: order/serializers.py:997 +msgid "The following serial numbers are already allocated" +msgstr "" + +#: order/templates/order/delete_attachment.html:5 +#: stock/templates/stock/attachment_delete.html:5 +msgid "Are you sure you want to delete this attachment?" +msgstr "" + +#: order/templates/order/order_base.html:33 +msgid "Print purchase order report" +msgstr "" + +#: order/templates/order/order_base.html:35 +#: order/templates/order/sales_order_base.html:45 +msgid "Export order to file" +msgstr "" + +#: order/templates/order/order_base.html:41 +#: order/templates/order/sales_order_base.html:54 +msgid "Order actions" +msgstr "" + +#: order/templates/order/order_base.html:45 +#: order/templates/order/sales_order_base.html:58 +msgid "Edit order" +msgstr "" + +#: order/templates/order/order_base.html:56 +msgid "Receive items" +msgstr "" + +#: order/templates/order/order_base.html:58 +#: order/templates/order/purchase_order_detail.html:30 +msgid "Receive Items" +msgstr "" + +#: order/templates/order/order_base.html:62 +#: order/templates/order/sales_order_base.html:67 order/views.py:181 +msgid "Complete Order" +msgstr "" + +#: order/templates/order/order_base.html:84 +#: order/templates/order/sales_order_base.html:79 +msgid "Order Reference" +msgstr "" + +#: order/templates/order/order_base.html:89 +#: order/templates/order/sales_order_base.html:84 +msgid "Order Description" +msgstr "" + +#: order/templates/order/order_base.html:94 +#: order/templates/order/sales_order_base.html:89 +msgid "Order Status" +msgstr "" + +#: order/templates/order/order_base.html:124 +#: order/templates/order/sales_order_base.html:128 +msgid "Completed Line Items" +msgstr "" + +#: order/templates/order/order_base.html:130 +#: order/templates/order/sales_order_base.html:134 +#: order/templates/order/sales_order_base.html:144 +msgid "Incomplete" +msgstr "" + +#: order/templates/order/order_base.html:149 +#: report/templates/report/inventree_build_order_base.html:122 +msgid "Issued" +msgstr "" + +#: order/templates/order/order_base.html:219 +msgid "Edit Purchase Order" +msgstr "" + +#: order/templates/order/order_cancel.html:8 +msgid "Cancelling this order means that the order and line items will no longer be editable." +msgstr "" + +#: order/templates/order/order_complete.html:7 +msgid "Mark this order as complete?" +msgstr "" + +#: order/templates/order/order_complete.html:10 +msgid "This order has line items which have not been marked as received." +msgstr "" + +#: order/templates/order/order_complete.html:11 +msgid "Completing this order means that the order and line items will no longer be editable." +msgstr "" + +#: order/templates/order/order_issue.html:8 +msgid "After placing this purchase order, line items will no longer be editable." +msgstr "" + +#: order/templates/order/order_wizard/match_parts.html:12 +#: 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:21 +#: part/templates/part/import_wizard/match_references.html:21 +#: templates/patterns/wizard/match_fields.html:28 +msgid "Submit Selections" +msgstr "" + +#: order/templates/order/order_wizard/match_parts.html:28 +#: 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:29 +msgid "Select Supplier Part" +msgstr "" + +#: order/templates/order/order_wizard/match_parts.html:52 +#: 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_references.html:49 +#: templates/js/translated/bom.js:76 templates/js/translated/build.js:381 +#: templates/js/translated/build.js:529 templates/js/translated/build.js:1588 +#: templates/js/translated/order.js:662 templates/js/translated/order.js:1693 +#: templates/js/translated/stock.js:569 templates/js/translated/stock.js:737 +#: templates/patterns/wizard/match_fields.html:70 +msgid "Remove row" +msgstr "" + +#: order/templates/order/order_wizard/po_upload.html:8 +msgid "Return to Orders" +msgstr "" + +#: order/templates/order/order_wizard/po_upload.html:13 +msgid "Upload File for Purchase Order" +msgstr "" + +#: order/templates/order/order_wizard/po_upload.html:14 +msgid "Order is already processed. Files cannot be uploaded." +msgstr "" + +#: 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:16 +msgid "Select suppliers" +msgstr "" + +#: order/templates/order/order_wizard/select_parts.html:20 +msgid "No purchaseable parts selected" +msgstr "" + +#: 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:77 +#: part/templates/part/set_category.html:32 +msgid "Remove part" +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:8 +msgid "Step 2 of 2 - Select Purchase Orders" +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:12 +msgid "Select existing purchase orders, or create new orders." +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:31 +#: templates/js/translated/order.js:1000 templates/js/translated/order.js:1491 +#: templates/js/translated/order.js:1621 +msgid "Items" +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:32 +msgid "Select Purchase Order" +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:45 +#, python-format +msgid "Create new purchase order for %(name)s" +msgstr "" + +#: order/templates/order/order_wizard/select_pos.html:68 +#, python-format +msgid "Select a purchase order for %(name)s" +msgstr "" + +#: order/templates/order/po_sidebar.html:5 +#: order/templates/order/so_sidebar.html:5 +#: report/templates/report/inventree_po_report.html:84 +#: report/templates/report/inventree_so_report.html:85 +msgid "Line Items" +msgstr "" + +#: order/templates/order/po_sidebar.html:7 +msgid "Received Stock" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:17 +msgid "Purchase Order Items" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:26 +#: order/templates/order/purchase_order_detail.html:159 +#: order/templates/order/sales_order_detail.html:22 +#: order/templates/order/sales_order_detail.html:226 +msgid "Add Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:29 +msgid "Receive selected items" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:49 +msgid "Received Items" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:74 +#: order/templates/order/sales_order_detail.html:121 +msgid "Order Notes" +msgstr "" + +#: order/templates/order/purchase_orders.html:30 +#: order/templates/order/sales_orders.html:33 +msgid "Print Order Reports" +msgstr "" + +#: order/templates/order/sales_order_base.html:43 +msgid "Print sales order report" +msgstr "" + +#: order/templates/order/sales_order_base.html:47 +msgid "Print packing list" +msgstr "" + +#: order/templates/order/sales_order_base.html:66 +#: order/templates/order/sales_order_base.html:229 +msgid "Complete Sales Order" +msgstr "" + +#: order/templates/order/sales_order_base.html:102 +msgid "This Sales Order has not been fully allocated" +msgstr "" + +#: order/templates/order/sales_order_base.html:122 +#: templates/js/translated/order.js:1449 +msgid "Customer Reference" +msgstr "" + +#: order/templates/order/sales_order_base.html:140 +#: order/templates/order/sales_order_detail.html:77 +#: order/templates/order/so_sidebar.html:11 +msgid "Completed Shipments" +msgstr "" + +#: order/templates/order/sales_order_base.html:215 +msgid "Edit Sales Order" +msgstr "" + +#: order/templates/order/sales_order_cancel.html:8 +#: stock/templates/stock/stockitem_convert.html:13 +msgid "Warning" +msgstr "" + +#: order/templates/order/sales_order_cancel.html:9 +msgid "Cancelling this order means that the order will no longer be editable." +msgstr "" + +#: order/templates/order/sales_order_detail.html:17 +msgid "Sales Order Items" +msgstr "" + +#: order/templates/order/sales_order_detail.html:43 +#: order/templates/order/so_sidebar.html:8 +msgid "Pending Shipments" +msgstr "" + +#: order/templates/order/sales_order_detail.html:47 +#: templates/js/translated/bom.js:953 templates/js/translated/build.js:1496 +msgid "Actions" +msgstr "" + +#: order/templates/order/sales_order_detail.html:56 +msgid "New Shipment" +msgstr "" + +#: order/views.py:99 +msgid "Cancel Order" +msgstr "" + +#: order/views.py:108 order/views.py:134 +msgid "Confirm order cancellation" +msgstr "" + +#: order/views.py:111 order/views.py:137 +msgid "Order cannot be cancelled" +msgstr "" + +#: order/views.py:125 +msgid "Cancel sales order" +msgstr "" + +#: order/views.py:151 +msgid "Issue Order" +msgstr "" + +#: order/views.py:160 +msgid "Confirm order placement" +msgstr "" + +#: order/views.py:170 +msgid "Purchase order issued" +msgstr "" + +#: order/views.py:197 +msgid "Confirm order completion" +msgstr "" + +#: order/views.py:208 +msgid "Purchase order completed" +msgstr "" + +#: order/views.py:245 +msgid "Match Supplier Parts" +msgstr "" + +#: order/views.py:489 +msgid "Update prices" +msgstr "" + +#: order/views.py:747 +#, python-brace-format +msgid "Ordered {n} parts" +msgstr "" + +#: order/views.py:858 +msgid "Sales order not found" +msgstr "" + +#: order/views.py:864 +msgid "Price not found" +msgstr "" + +#: order/views.py:867 +#, python-brace-format +msgid "Updated {part} unit-price to {price}" +msgstr "" + +#: order/views.py:872 +#, python-brace-format +msgid "Updated {part} unit-price to {price} and quantity to {qty}" +msgstr "" + +#: part/api.py:491 +msgid "Incoming Purchase Order" +msgstr "" + +#: part/api.py:511 +msgid "Outgoing Sales Order" +msgstr "" + +#: part/api.py:529 +msgid "Stock produced by Build Order" +msgstr "" + +#: part/api.py:561 +msgid "Stock required for Build Order" +msgstr "" + +#: part/api.py:641 +msgid "Valid" +msgstr "" + +#: part/api.py:642 +msgid "Validate entire Bill of Materials" +msgstr "" + +#: part/api.py:647 +msgid "This option must be selected" +msgstr "" + +#: part/api.py:1027 +msgid "Must be greater than zero" +msgstr "" + +#: part/api.py:1031 +msgid "Must be a valid quantity" +msgstr "" + +#: part/api.py:1046 +msgid "Specify location for initial part stock" +msgstr "" + +#: part/api.py:1077 part/api.py:1081 part/api.py:1096 part/api.py:1100 +msgid "This field is required" +msgstr "" + +#: part/bom.py:125 part/models.py:112 part/models.py:887 +#: part/templates/part/category.html:108 part/templates/part/part_base.html:356 +msgid "Default Location" +msgstr "" + +#: part/bom.py:126 templates/email/low_stock_notification.html:17 +msgid "Total Stock" +msgstr "" + +#: part/bom.py:127 part/templates/part/part_base.html:189 +msgid "Available Stock" +msgstr "" + +#: part/bom.py:128 part/templates/part/part_base.html:207 +#: templates/js/translated/part.js:512 templates/js/translated/part.js:532 +#: templates/js/translated/part.js:1211 templates/js/translated/part.js:1383 +#: templates/js/translated/part.js:1399 +msgid "On Order" +msgstr "" + +#: part/forms.py:84 +msgid "Select part category" +msgstr "" + +#: part/forms.py:121 +msgid "Add parameter template to same level categories" +msgstr "" + +#: part/forms.py:125 +msgid "Add parameter template to all categories" +msgstr "" + +#: part/forms.py:145 +msgid "Input quantity for price calculation" +msgstr "" + +#: part/models.py:113 +msgid "Default location for parts in this category" +msgstr "" + +#: part/models.py:116 +msgid "Default keywords" +msgstr "" + +#: part/models.py:116 +msgid "Default keywords for parts in this category" +msgstr "" + +#: part/models.py:126 part/models.py:2637 part/templates/part/category.html:15 +#: part/templates/part/part_app_base.html:10 +msgid "Part Category" +msgstr "" + +#: part/models.py:127 part/templates/part/category.html:128 +#: templates/InvenTree/search.html:95 templates/js/translated/search.js:113 +#: templates/stats.html:96 users/models.py:40 +msgid "Part Categories" +msgstr "" + +#: part/models.py:368 part/templates/part/cat_link.html:3 +#: part/templates/part/category.html:17 part/templates/part/category.html:133 +#: part/templates/part/category.html:153 +#: part/templates/part/category_sidebar.html:9 +#: templates/InvenTree/index.html:85 templates/InvenTree/search.html:82 +#: templates/InvenTree/settings/sidebar.html:39 +#: templates/js/translated/part.js:1762 templates/js/translated/search.js:99 +#: templates/navbar.html:21 templates/stats.html:92 templates/stats.html:101 +#: users/models.py:41 +msgid "Parts" +msgstr "" + +#: part/models.py:460 +msgid "Invalid choice for parent part" +msgstr "" + +#: part/models.py:540 part/models.py:552 +#, python-brace-format +msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" +msgstr "" + +#: part/models.py:682 +msgid "Next available serial numbers are" +msgstr "" + +#: part/models.py:686 +msgid "Next available serial number is" +msgstr "" + +#: part/models.py:691 +msgid "Most recent serial number is" +msgstr "" + +#: part/models.py:786 +msgid "Duplicate IPN not allowed in part settings" +msgstr "" + +#: part/models.py:811 part/models.py:2690 +msgid "Part name" +msgstr "" + +#: part/models.py:818 +msgid "Is Template" +msgstr "" + +#: part/models.py:819 +msgid "Is this part a template part?" +msgstr "" + +#: part/models.py:829 +msgid "Is this part a variant of another part?" +msgstr "" + +#: part/models.py:830 +msgid "Variant Of" +msgstr "" + +#: part/models.py:836 +msgid "Part description" +msgstr "" + +#: part/models.py:841 part/templates/part/category.html:86 +#: part/templates/part/part_base.html:320 +msgid "Keywords" +msgstr "" + +#: part/models.py:842 +msgid "Part keywords to improve visibility in search results" +msgstr "" + +#: part/models.py:849 part/models.py:2387 part/models.py:2636 +#: part/templates/part/part_base.html:283 +#: part/templates/part/set_category.html:15 +#: templates/InvenTree/notifications/notifications.html:65 +#: templates/InvenTree/settings/settings.html:224 +#: templates/js/translated/part.js:1351 +msgid "Category" +msgstr "" + +#: part/models.py:850 +msgid "Part category" +msgstr "" + +#: part/models.py:855 part/templates/part/part_base.html:292 +#: templates/js/translated/part.js:661 templates/js/translated/part.js:1304 +#: templates/js/translated/stock.js:1668 +msgid "IPN" +msgstr "" + +#: part/models.py:856 +msgid "Internal Part Number" +msgstr "" + +#: part/models.py:862 +msgid "Part revision or version number" +msgstr "" + +#: part/models.py:863 part/templates/part/part_base.html:299 +#: report/models.py:196 templates/js/translated/part.js:665 +msgid "Revision" +msgstr "" + +#: part/models.py:885 +msgid "Where is this item normally stored?" +msgstr "" + +#: part/models.py:932 part/templates/part/part_base.html:365 +msgid "Default Supplier" +msgstr "" + +#: part/models.py:933 +msgid "Default supplier part" +msgstr "" + +#: part/models.py:940 +msgid "Default Expiry" +msgstr "" + +#: part/models.py:941 +msgid "Expiry time (in days) for stock items of this part" +msgstr "" + +#: part/models.py:946 part/templates/part/part_base.html:200 +msgid "Minimum Stock" +msgstr "" + +#: part/models.py:947 +msgid "Minimum allowed stock level" +msgstr "" + +#: part/models.py:954 +msgid "Stock keeping units for this part" +msgstr "" + +#: part/models.py:960 +msgid "Can this part be built from other parts?" +msgstr "" + +#: part/models.py:966 +msgid "Can this part be used to build other parts?" +msgstr "" + +#: part/models.py:972 +msgid "Does this part have tracking for unique items?" +msgstr "" + +#: part/models.py:977 +msgid "Can this part be purchased from external suppliers?" +msgstr "" + +#: part/models.py:982 +msgid "Can this part be sold to customers?" +msgstr "" + +#: part/models.py:987 +msgid "Is this part active?" +msgstr "" + +#: part/models.py:992 +msgid "Is this a virtual part, such as a software product or license?" +msgstr "" + +#: part/models.py:997 +msgid "Part notes - supports Markdown formatting" +msgstr "" + +#: part/models.py:1000 +msgid "BOM checksum" +msgstr "" + +#: part/models.py:1000 +msgid "Stored BOM checksum" +msgstr "" + +#: part/models.py:1003 +msgid "BOM checked by" +msgstr "" + +#: part/models.py:1005 +msgid "BOM checked date" +msgstr "" + +#: part/models.py:1009 +msgid "Creation User" +msgstr "" + +#: part/models.py:1873 +msgid "Sell multiple" +msgstr "" + +#: part/models.py:2437 +msgid "Test templates can only be created for trackable parts" +msgstr "" + +#: part/models.py:2454 +msgid "Test with this name already exists for this part" +msgstr "" + +#: part/models.py:2474 templates/js/translated/part.js:1813 +#: templates/js/translated/stock.js:1283 +msgid "Test Name" +msgstr "" + +#: part/models.py:2475 +msgid "Enter a name for the test" +msgstr "" + +#: part/models.py:2480 +msgid "Test Description" +msgstr "" + +#: part/models.py:2481 +msgid "Enter description for this test" +msgstr "" + +#: part/models.py:2486 templates/js/translated/part.js:1822 +#: templates/js/translated/table_filters.js:294 +msgid "Required" +msgstr "" + +#: part/models.py:2487 +msgid "Is this test required to pass?" +msgstr "" + +#: part/models.py:2492 templates/js/translated/part.js:1830 +msgid "Requires Value" +msgstr "" + +#: part/models.py:2493 +msgid "Does this test require a value when adding a test result?" +msgstr "" + +#: part/models.py:2498 templates/js/translated/part.js:1837 +msgid "Requires Attachment" +msgstr "" + +#: part/models.py:2499 +msgid "Does this test require a file attachment when adding a test result?" +msgstr "" + +#: part/models.py:2510 +#, python-brace-format +msgid "Illegal character in template name ({c})" +msgstr "" + +#: part/models.py:2546 +msgid "Parameter template name must be unique" +msgstr "" + +#: part/models.py:2554 +msgid "Parameter Name" +msgstr "" + +#: part/models.py:2561 +msgid "Parameter Units" +msgstr "" + +#: part/models.py:2591 +msgid "Parent Part" +msgstr "" + +#: part/models.py:2593 part/models.py:2642 part/models.py:2643 +#: templates/InvenTree/settings/settings.html:219 +msgid "Parameter Template" +msgstr "" + +#: part/models.py:2595 +msgid "Data" +msgstr "" + +#: part/models.py:2595 +msgid "Parameter Value" +msgstr "" + +#: part/models.py:2647 templates/InvenTree/settings/settings.html:228 +msgid "Default Value" +msgstr "" + +#: part/models.py:2648 +msgid "Default Parameter Value" +msgstr "" + +#: part/models.py:2682 +msgid "Part ID or part name" +msgstr "" + +#: part/models.py:2685 templates/js/translated/model_renderers.js:203 +msgid "Part ID" +msgstr "" + +#: part/models.py:2686 +msgid "Unique part ID value" +msgstr "" + +#: part/models.py:2689 +msgid "Part Name" +msgstr "" + +#: part/models.py:2693 +msgid "Part IPN" +msgstr "" + +#: part/models.py:2694 +msgid "Part IPN value" +msgstr "" + +#: part/models.py:2697 +msgid "Level" +msgstr "" + +#: part/models.py:2698 +msgid "BOM level" +msgstr "" + +#: part/models.py:2759 +msgid "Select parent part" +msgstr "" + +#: part/models.py:2767 +msgid "Sub part" +msgstr "" + +#: part/models.py:2768 +msgid "Select part to be used in BOM" +msgstr "" + +#: part/models.py:2774 +msgid "BOM quantity for this BOM item" +msgstr "" + +#: part/models.py:2776 part/templates/part/upload_bom.html:58 +#: templates/js/translated/bom.js:789 templates/js/translated/bom.js:871 +#: templates/js/translated/table_filters.js:92 +msgid "Optional" +msgstr "" + +#: part/models.py:2776 +msgid "This BOM item is optional" +msgstr "" + +#: part/models.py:2779 part/templates/part/upload_bom.html:55 +msgid "Overage" +msgstr "" + +#: part/models.py:2780 +msgid "Estimated build wastage quantity (absolute or percentage)" +msgstr "" + +#: part/models.py:2783 +msgid "BOM item reference" +msgstr "" + +#: part/models.py:2786 +msgid "BOM item notes" +msgstr "" + +#: part/models.py:2788 +msgid "Checksum" +msgstr "" + +#: part/models.py:2788 +msgid "BOM line checksum" +msgstr "" + +#: part/models.py:2792 part/templates/part/upload_bom.html:57 +#: templates/js/translated/bom.js:888 +#: templates/js/translated/table_filters.js:68 +#: templates/js/translated/table_filters.js:88 +msgid "Inherited" +msgstr "" + +#: part/models.py:2793 +msgid "This BOM item is inherited by BOMs for variant parts" +msgstr "" + +#: part/models.py:2798 part/templates/part/upload_bom.html:56 +#: templates/js/translated/bom.js:880 +msgid "Allow Variants" +msgstr "" + +#: part/models.py:2799 +msgid "Stock items for variant parts can be used for this BOM item" +msgstr "" + +#: part/models.py:2884 stock/models.py:467 +msgid "Quantity must be integer value for trackable parts" +msgstr "" + +#: part/models.py:2893 part/models.py:2895 +msgid "Sub part must be specified" +msgstr "" + +#: part/models.py:3007 +msgid "BOM Item Substitute" +msgstr "" + +#: part/models.py:3029 +msgid "Substitute part cannot be the same as the master part" +msgstr "" + +#: part/models.py:3041 +msgid "Parent BOM item" +msgstr "" + +#: part/models.py:3049 +msgid "Substitute part" +msgstr "" + +#: part/models.py:3060 +msgid "Part 1" +msgstr "" + +#: part/models.py:3064 +msgid "Part 2" +msgstr "" + +#: part/models.py:3064 +msgid "Select Related Part" +msgstr "" + +#: part/models.py:3096 +msgid "Error creating relationship: check that the part is not related to itself and that the relationship is unique" +msgstr "" + +#: part/serializers.py:835 +msgid "Select part to copy BOM from" +msgstr "" + +#: part/serializers.py:846 +msgid "Remove Existing Data" +msgstr "" + +#: part/serializers.py:847 +msgid "Remove existing BOM items before copying" +msgstr "" + +#: part/serializers.py:852 +msgid "Include Inherited" +msgstr "" + +#: part/serializers.py:853 +msgid "Include BOM items which are inherited from templated parts" +msgstr "" + +#: part/serializers.py:858 +msgid "Skip Invalid Rows" +msgstr "" + +#: part/serializers.py:859 +msgid "Enable this option to skip invalid rows" +msgstr "" + +#: part/serializers.py:864 +msgid "Copy Substitute Parts" +msgstr "" + +#: part/serializers.py:865 +msgid "Copy substitute parts when duplicate BOM items" +msgstr "" + +#: part/serializers.py:909 +msgid "Clear Existing BOM" +msgstr "" + +#: part/serializers.py:910 +msgid "Delete existing BOM items before uploading" +msgstr "" + +#: part/serializers.py:937 +msgid "No part column specified" +msgstr "" + +#: part/serializers.py:980 +msgid "Multiple matching parts found" +msgstr "" + +#: part/serializers.py:983 +msgid "No matching part found" +msgstr "" + +#: part/serializers.py:986 +msgid "Part is not designated as a component" +msgstr "" + +#: part/serializers.py:995 +msgid "Quantity not provided" +msgstr "" + +#: part/serializers.py:1003 +msgid "Invalid quantity" +msgstr "" + +#: part/serializers.py:1022 +msgid "At least one BOM item is required" +msgstr "" + +#: part/tasks.py:18 +msgid "Low stock notification" +msgstr "" + +#: part/tasks.py:19 +#, python-brace-format +msgid "The available stock for {part.name} has fallen below the configured minimum level" +msgstr "" + +#: part/templates/part/bom.html:6 +msgid "You do not have permission to edit the BOM." +msgstr "" + +#: part/templates/part/bom.html:15 +#, python-format +msgid "The BOM for %(part)s has changed, and must be validated.
        " +msgstr "" + +#: part/templates/part/bom.html:17 +#, python-format +msgid "The BOM for %(part)s was last checked by %(checker)s on %(check_date)s" +msgstr "" + +#: part/templates/part/bom.html:21 +#, python-format +msgid "The BOM for %(part)s has not been validated." +msgstr "" + +#: part/templates/part/bom.html:30 part/templates/part/detail.html:263 +msgid "BOM actions" +msgstr "" + +#: part/templates/part/bom.html:34 +msgid "Delete Items" +msgstr "" + +#: part/templates/part/category.html:28 part/templates/part/category.html:32 +msgid "You are subscribed to notifications for this category" +msgstr "" + +#: part/templates/part/category.html:36 +msgid "Subscribe to notifications for this category" +msgstr "" + +#: part/templates/part/category.html:42 +msgid "Category Actions" +msgstr "" + +#: part/templates/part/category.html:47 +msgid "Edit category" +msgstr "" + +#: part/templates/part/category.html:48 +msgid "Edit Category" +msgstr "" + +#: part/templates/part/category.html:52 +msgid "Delete category" +msgstr "" + +#: part/templates/part/category.html:53 +msgid "Delete Category" +msgstr "" + +#: part/templates/part/category.html:61 +msgid "Create new part category" +msgstr "" + +#: part/templates/part/category.html:62 +msgid "New Category" +msgstr "" + +#: part/templates/part/category.html:80 part/templates/part/category.html:93 +msgid "Category Path" +msgstr "" + +#: part/templates/part/category.html:94 +msgid "Top level part category" +msgstr "" + +#: part/templates/part/category.html:114 part/templates/part/category.html:211 +#: part/templates/part/category_sidebar.html:7 +msgid "Subcategories" +msgstr "" + +#: part/templates/part/category.html:119 +msgid "Parts (Including subcategories)" +msgstr "" + +#: part/templates/part/category.html:157 +msgid "Create new part" +msgstr "" + +#: part/templates/part/category.html:158 templates/js/translated/bom.js:365 +msgid "New Part" +msgstr "" + +#: part/templates/part/category.html:172 +msgid "Set category" +msgstr "" + +#: part/templates/part/category.html:172 +msgid "Set Category" +msgstr "" + +#: part/templates/part/category.html:176 +msgid "Print Labels" +msgstr "" + +#: part/templates/part/category.html:178 +msgid "Export" +msgstr "" + +#: part/templates/part/category.html:178 +msgid "Export Data" +msgstr "" + +#: part/templates/part/category.html:201 +msgid "Part Parameters" +msgstr "" + +#: part/templates/part/category.html:309 +msgid "Create Part Category" +msgstr "" + +#: part/templates/part/category.html:329 +msgid "Create Part" +msgstr "" + +#: part/templates/part/category.html:332 +msgid "Create another part after this one" +msgstr "" + +#: part/templates/part/category.html:333 +msgid "Part created successfully" +msgstr "" + +#: part/templates/part/category_delete.html:7 +msgid "Are you sure you want to delete this part category?" +msgstr "" + +#: part/templates/part/category_delete.html:12 +#, python-format +msgid "This category contains %(n)s child categories" +msgstr "" + +#: part/templates/part/category_delete.html:14 +#, python-format +msgid "If this category is deleted, these child categories will be moved to %(category)s" +msgstr "" + +#: part/templates/part/category_delete.html:16 +msgid "If this category is deleted, these child categories will be moved to the top level part category" +msgstr "" + +#: part/templates/part/category_delete.html:23 +#, python-format +msgid "This category contains %(n)s parts" +msgstr "" + +#: part/templates/part/category_delete.html:25 +#, python-format +msgid "If this category is deleted, these parts will be moved to %(category)s" +msgstr "" + +#: part/templates/part/category_delete.html:27 +msgid "If this category is deleted, these parts will be moved to the top level part category" +msgstr "" + +#: part/templates/part/category_sidebar.html:13 +msgid "Import Parts" +msgstr "" + +#: part/templates/part/copy_part.html:9 templates/js/translated/part.js:350 +msgid "Duplicate Part" +msgstr "" + +#: part/templates/part/copy_part.html:10 +#, python-format +msgid "Make a copy of part '%(full_name)s'." +msgstr "" + +#: part/templates/part/copy_part.html:14 +#: part/templates/part/create_part.html:11 +msgid "Possible Matching Parts" +msgstr "" + +#: part/templates/part/copy_part.html:15 +#: part/templates/part/create_part.html:12 +msgid "The new part may be a duplicate of these existing parts" +msgstr "" + +#: part/templates/part/create_part.html:17 +#, python-format +msgid "%(full_name)s - %(desc)s (%(match_per)s%% match)" +msgstr "" + +#: part/templates/part/detail.html:20 +msgid "Part Stock" +msgstr "" + +#: part/templates/part/detail.html:52 +msgid "Part Test Templates" +msgstr "" + +#: part/templates/part/detail.html:57 +msgid "Add Test Template" +msgstr "" + +#: part/templates/part/detail.html:114 stock/templates/stock/item.html:58 +msgid "Sales Order Allocations" +msgstr "" + +#: part/templates/part/detail.html:137 +msgid "Part Notes" +msgstr "" + +#: part/templates/part/detail.html:152 +msgid "Part Variants" +msgstr "" + +#: part/templates/part/detail.html:156 +msgid "Create new variant" +msgstr "" + +#: part/templates/part/detail.html:157 +msgid "New Variant" +msgstr "" + +#: part/templates/part/detail.html:184 +msgid "Add new parameter" +msgstr "" + +#: part/templates/part/detail.html:221 part/templates/part/part_sidebar.html:55 +msgid "Related Parts" +msgstr "" + +#: part/templates/part/detail.html:225 part/templates/part/detail.html:226 +msgid "Add Related" +msgstr "" + +#: part/templates/part/detail.html:246 part/templates/part/part_sidebar.html:18 +msgid "Bill of Materials" +msgstr "" + +#: part/templates/part/detail.html:251 +msgid "Export actions" +msgstr "" + +#: part/templates/part/detail.html:255 templates/js/translated/bom.js:283 +msgid "Export BOM" +msgstr "" + +#: part/templates/part/detail.html:257 +msgid "Print BOM Report" +msgstr "" + +#: part/templates/part/detail.html:267 +msgid "Upload BOM" +msgstr "" + +#: part/templates/part/detail.html:268 templates/js/translated/part.js:273 +msgid "Copy BOM" +msgstr "" + +#: part/templates/part/detail.html:269 +msgid "Validate BOM" +msgstr "" + +#: part/templates/part/detail.html:274 +msgid "New BOM Item" +msgstr "" + +#: part/templates/part/detail.html:275 +msgid "Add BOM Item" +msgstr "" + +#: part/templates/part/detail.html:288 +msgid "Assemblies" +msgstr "" + +#: part/templates/part/detail.html:306 +msgid "Part Builds" +msgstr "" + +#: part/templates/part/detail.html:333 stock/templates/stock/item.html:43 +msgid "Build Order Allocations" +msgstr "" + +#: part/templates/part/detail.html:349 +msgid "Part Suppliers" +msgstr "" + +#: part/templates/part/detail.html:377 +msgid "Part Manufacturers" +msgstr "" + +#: part/templates/part/detail.html:393 +msgid "Delete manufacturer parts" +msgstr "" + +#: part/templates/part/detail.html:596 +msgid "Delete selected BOM items?" +msgstr "" + +#: part/templates/part/detail.html:597 +msgid "All selected BOM items will be deleted" +msgstr "" + +#: part/templates/part/detail.html:646 +msgid "Create BOM Item" +msgstr "" + +#: part/templates/part/detail.html:690 +msgid "Related Part" +msgstr "" + +#: part/templates/part/detail.html:698 +msgid "Add Related Part" +msgstr "" + +#: part/templates/part/detail.html:795 +msgid "Add Test Result Template" +msgstr "" + +#: part/templates/part/detail.html:928 +#, python-format +msgid "Purchase Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/detail.html:940 +#, python-format +msgid "Unit Price-Cost Difference - %(currency)s" +msgstr "" + +#: part/templates/part/detail.html:952 +#, python-format +msgid "Supplier Unit Cost - %(currency)s" +msgstr "" + +#: part/templates/part/detail.html:1041 +#, python-format +msgid "Unit Price - %(currency)s" +msgstr "" + +#: part/templates/part/import_wizard/ajax_match_fields.html:9 +#: templates/patterns/wizard/match_fields.html:8 +msgid "Missing selections for the following required columns" +msgstr "" + +#: part/templates/part/import_wizard/ajax_match_fields.html:20 +#: templates/patterns/wizard/match_fields.html:19 +msgid "Duplicate selections found, see below. Fix them then retry submitting." +msgstr "" + +#: part/templates/part/import_wizard/ajax_match_fields.html:28 +#: templates/patterns/wizard/match_fields.html:34 +msgid "File Fields" +msgstr "" + +#: part/templates/part/import_wizard/ajax_match_fields.html:35 +#: templates/patterns/wizard/match_fields.html:41 +msgid "Remove column" +msgstr "" + +#: part/templates/part/import_wizard/ajax_match_fields.html:53 +#: templates/patterns/wizard/match_fields.html:59 +msgid "Duplicate selection" +msgstr "" + +#: part/templates/part/import_wizard/ajax_part_upload.html:10 +#: templates/patterns/wizard/upload.html:13 +#, python-format +msgid "Step %(step)s of %(count)s" +msgstr "" + +#: part/templates/part/import_wizard/ajax_part_upload.html:29 +#: part/templates/part/import_wizard/part_upload.html:14 +msgid "Unsuffitient privileges." +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:8 +msgid "Return to Parts" +msgstr "" + +#: part/templates/part/import_wizard/part_upload.html:13 +msgid "Import Parts from File" +msgstr "" + +#: part/templates/part/part_app_base.html:12 +msgid "Part List" +msgstr "" + +#: part/templates/part/part_base.html:27 part/templates/part/part_base.html:31 +msgid "You are subscribed to notifications for this part" +msgstr "" + +#: part/templates/part/part_base.html:35 +msgid "Subscribe to notifications for this part" +msgstr "" + +#: part/templates/part/part_base.html:43 +#: stock/templates/stock/item_base.html:35 +#: stock/templates/stock/location.html:34 +msgid "Barcode actions" +msgstr "" + +#: part/templates/part/part_base.html:46 +#: stock/templates/stock/item_base.html:39 +#: stock/templates/stock/location.html:36 templates/qr_button.html:1 +msgid "Show QR Code" +msgstr "" + +#: part/templates/part/part_base.html:49 +#: stock/templates/stock/item_base.html:57 +#: stock/templates/stock/location.html:38 +msgid "Print Label" +msgstr "" + +#: part/templates/part/part_base.html:55 +msgid "Show pricing information" +msgstr "" + +#: part/templates/part/part_base.html:60 +#: stock/templates/stock/item_base.html:110 +#: stock/templates/stock/location.html:47 +msgid "Stock actions" +msgstr "" + +#: part/templates/part/part_base.html:67 +msgid "Count part stock" +msgstr "" + +#: part/templates/part/part_base.html:73 +msgid "Transfer part stock" +msgstr "" + +#: part/templates/part/part_base.html:88 +msgid "Part actions" +msgstr "" + +#: part/templates/part/part_base.html:91 +msgid "Duplicate part" +msgstr "" + +#: part/templates/part/part_base.html:94 +msgid "Edit part" +msgstr "" + +#: part/templates/part/part_base.html:97 +msgid "Delete part" +msgstr "" + +#: part/templates/part/part_base.html:116 +msgid "Part is a template part (variants can be made from this part)" +msgstr "" + +#: part/templates/part/part_base.html:120 +msgid "Part can be assembled from other parts" +msgstr "" + +#: part/templates/part/part_base.html:124 +msgid "Part can be used in assemblies" +msgstr "" + +#: part/templates/part/part_base.html:128 +msgid "Part stock is tracked by serial number" +msgstr "" + +#: part/templates/part/part_base.html:132 +msgid "Part can be purchased from external suppliers" +msgstr "" + +#: part/templates/part/part_base.html:136 +msgid "Part can be sold to customers" +msgstr "" + +#: part/templates/part/part_base.html:142 +#: part/templates/part/part_base.html:150 +msgid "Part is virtual (not a physical part)" +msgstr "" + +#: part/templates/part/part_base.html:143 +#: templates/js/translated/company.js:508 +#: templates/js/translated/company.js:765 +#: templates/js/translated/model_renderers.js:195 +#: templates/js/translated/part.js:576 templates/js/translated/part.js:653 +msgid "Inactive" +msgstr "" + +#: part/templates/part/part_base.html:160 +#: part/templates/part/part_base.html:599 +msgid "Show Part Details" +msgstr "" + +#: part/templates/part/part_base.html:177 +#, python-format +msgid "This part is a variant of %(link)s" +msgstr "" + +#: part/templates/part/part_base.html:194 templates/js/translated/order.js:2436 +#: templates/js/translated/table_filters.js:193 +msgid "In Stock" +msgstr "" + +#: part/templates/part/part_base.html:215 templates/InvenTree/index.html:178 +msgid "Required for Build Orders" +msgstr "" + +#: part/templates/part/part_base.html:220 +msgid "Allocated to Build Orders" +msgstr "" + +#: part/templates/part/part_base.html:224 +#: part/templates/part/part_base.html:247 +msgid "Required quantity has not been allocated" +msgstr "" + +#: part/templates/part/part_base.html:226 +#: part/templates/part/part_base.html:249 +msgid "Required quantity has been allocated" +msgstr "" + +#: part/templates/part/part_base.html:236 +msgid "Required for Sales Orders" +msgstr "" + +#: part/templates/part/part_base.html:243 +msgid "Allocated to Sales Orders" +msgstr "" + +#: part/templates/part/part_base.html:258 templates/js/translated/bom.js:909 +msgid "Can Build" +msgstr "" + +#: part/templates/part/part_base.html:264 templates/js/translated/part.js:515 +#: templates/js/translated/part.js:535 templates/js/translated/part.js:1215 +#: templates/js/translated/part.js:1387 templates/js/translated/part.js:1403 +msgid "Building" +msgstr "" + +#: part/templates/part/part_base.html:313 +msgid "Minimum stock level" +msgstr "" + +#: part/templates/part/part_base.html:342 +msgid "Latest Serial Number" +msgstr "" + +#: part/templates/part/part_base.html:346 +#: stock/templates/stock/item_base.html:166 +msgid "Search for serial number" +msgstr "" + +#: part/templates/part/part_base.html:469 part/templates/part/prices.html:144 +msgid "Calculate" +msgstr "" + +#: part/templates/part/part_base.html:512 +msgid "No matching images found" +msgstr "" + +#: part/templates/part/part_base.html:593 +msgid "Hide Part Details" +msgstr "" + +#: part/templates/part/part_pricing.html:22 part/templates/part/prices.html:21 +msgid "Supplier Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:26 +#: part/templates/part/part_pricing.html:52 +#: part/templates/part/part_pricing.html:100 +#: part/templates/part/part_pricing.html:115 part/templates/part/prices.html:25 +#: part/templates/part/prices.html:52 part/templates/part/prices.html:103 +#: part/templates/part/prices.html:120 +msgid "Unit Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:32 +#: part/templates/part/part_pricing.html:58 +#: part/templates/part/part_pricing.html:104 +#: part/templates/part/part_pricing.html:119 part/templates/part/prices.html:32 +#: part/templates/part/prices.html:59 part/templates/part/prices.html:108 +#: part/templates/part/prices.html:125 +msgid "Total Cost" +msgstr "" + +#: part/templates/part/part_pricing.html:40 part/templates/part/prices.html:40 +#: templates/js/translated/bom.js:863 +msgid "No supplier pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:48 part/templates/part/prices.html:49 +#: part/templates/part/prices.html:243 +msgid "BOM Pricing" +msgstr "" + +#: part/templates/part/part_pricing.html:65 part/templates/part/prices.html:69 +msgid "Unit Purchase Price" +msgstr "" + +#: part/templates/part/part_pricing.html:71 part/templates/part/prices.html:76 +msgid "Total Purchase Price" +msgstr "" + +#: part/templates/part/part_pricing.html:81 part/templates/part/prices.html:86 +msgid "Note: BOM pricing is incomplete for this part" +msgstr "" + +#: part/templates/part/part_pricing.html:88 part/templates/part/prices.html:93 +msgid "No BOM pricing available" +msgstr "" + +#: part/templates/part/part_pricing.html:97 part/templates/part/prices.html:102 +msgid "Internal Price" +msgstr "" + +#: part/templates/part/part_pricing.html:128 +#: part/templates/part/prices.html:134 +msgid "No pricing information is available for this part." +msgstr "" + +#: part/templates/part/part_sidebar.html:12 +msgid "Variants" +msgstr "" + +#: part/templates/part/part_sidebar.html:28 +msgid "Used In" +msgstr "" + +#: part/templates/part/part_sidebar.html:47 +msgid "Scheduling" +msgstr "" + +#: part/templates/part/part_sidebar.html:51 +msgid "Test Templates" +msgstr "" + +#: part/templates/part/part_thumb.html:11 +msgid "Select from existing images" +msgstr "" + +#: part/templates/part/partial_delete.html:9 +#, python-format +msgid "" +"Part '%(full_name)s' cannot be deleted as it is still marked as active.\n" +"
        Disable the \"Active\" part attribute and re-try.\n" +" " +msgstr "" + +#: part/templates/part/partial_delete.html:17 +#, python-format +msgid "Are you sure you want to delete part '%(full_name)s'?" +msgstr "" + +#: part/templates/part/partial_delete.html:22 +#, python-format +msgid "This part is used in BOMs for %(count)s other parts. If you delete this part, the BOMs for the following parts will be updated" +msgstr "" + +#: part/templates/part/partial_delete.html:32 +#, python-format +msgid "There are %(count)s stock entries defined for this part. If you delete this part, the following stock entries will also be deleted:" +msgstr "" + +#: part/templates/part/partial_delete.html:43 +#, python-format +msgid "There are %(count)s manufacturers defined for this part. If you delete this part, the following manufacturer parts will also be deleted:" +msgstr "" + +#: part/templates/part/partial_delete.html:54 +#, 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 "" + +#: part/templates/part/partial_delete.html:65 +#, 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/prices.html:16 +msgid "Pricing ranges" +msgstr "" + +#: part/templates/part/prices.html:22 +msgid "Show supplier cost" +msgstr "" + +#: part/templates/part/prices.html:23 +msgid "Show purchase price" +msgstr "" + +#: part/templates/part/prices.html:50 +msgid "Show BOM cost" +msgstr "" + +#: part/templates/part/prices.html:117 +msgid "Show sale cost" +msgstr "" + +#: part/templates/part/prices.html:118 +msgid "Show sale price" +msgstr "" + +#: part/templates/part/prices.html:140 +msgid "Calculation parameters" +msgstr "" + +#: part/templates/part/prices.html:155 templates/js/translated/bom.js:857 +msgid "Supplier Cost" +msgstr "" + +#: part/templates/part/prices.html:156 part/templates/part/prices.html:177 +#: part/templates/part/prices.html:201 part/templates/part/prices.html:231 +#: part/templates/part/prices.html:257 part/templates/part/prices.html:285 +msgid "Jump to overview" +msgstr "" + +#: part/templates/part/prices.html:181 +msgid "Stock Pricing" +msgstr "" + +#: part/templates/part/prices.html:190 +msgid "No stock pricing history is available for this part." +msgstr "" + +#: part/templates/part/prices.html:200 +msgid "Internal Cost" +msgstr "" + +#: part/templates/part/prices.html:215 part/views.py:1309 +msgid "Add Internal Price Break" +msgstr "" + +#: part/templates/part/prices.html:230 +msgid "BOM Cost" +msgstr "" + +#: part/templates/part/prices.html:256 +msgid "Sale Cost" +msgstr "" + +#: part/templates/part/prices.html:296 +msgid "No sale pice history available for this part." +msgstr "" + +#: part/templates/part/set_category.html:9 +msgid "Set category for the following parts" +msgstr "" + +#: part/templates/part/stock_count.html:7 templates/js/translated/part.js:538 +#: templates/js/translated/part.js:1203 templates/js/translated/part.js:1407 +msgid "No Stock" +msgstr "" + +#: part/templates/part/stock_count.html:9 templates/InvenTree/index.html:158 +msgid "Low Stock" +msgstr "" + +#: part/templates/part/upload_bom.html:8 +msgid "Return to BOM" +msgstr "" + +#: part/templates/part/upload_bom.html:13 +msgid "Upload Bill of Materials" +msgstr "" + +#: part/templates/part/upload_bom.html:19 +msgid "BOM upload requirements" +msgstr "" + +#: part/templates/part/upload_bom.html:23 +#: part/templates/part/upload_bom.html:90 +msgid "Upload BOM File" +msgstr "" + +#: part/templates/part/upload_bom.html:29 +msgid "Submit BOM Data" +msgstr "" + +#: part/templates/part/upload_bom.html:37 +msgid "Requirements for BOM upload" +msgstr "" + +#: part/templates/part/upload_bom.html:39 +msgid "The BOM file must contain the required named columns as provided in the " +msgstr "" + +#: part/templates/part/upload_bom.html:39 +msgid "BOM Upload Template" +msgstr "" + +#: part/templates/part/upload_bom.html:40 +msgid "Each part must already exist in the database" +msgstr "" + +#: part/templates/part/variant_part.html:9 +msgid "Create new part variant" +msgstr "" + +#: part/templates/part/variant_part.html:10 +#, python-format +msgid "Create a new variant of template '%(full_name)s'." +msgstr "" + +#: part/templatetags/inventree_extras.py:189 +msgid "Unknown database" +msgstr "" + +#: part/views.py:88 +msgid "Set Part Category" +msgstr "" + +#: part/views.py:138 +#, python-brace-format +msgid "Set category for {n} parts" +msgstr "" + +#: part/views.py:210 +msgid "Match References" +msgstr "" + +#: part/views.py:507 +msgid "None" +msgstr "" + +#: part/views.py:566 +msgid "Part QR Code" +msgstr "" + +#: part/views.py:668 +msgid "Select Part Image" +msgstr "" + +#: part/views.py:694 +msgid "Updated part image" +msgstr "" + +#: part/views.py:697 +msgid "Part image not found" +msgstr "" + +#: part/views.py:785 +msgid "Confirm Part Deletion" +msgstr "" + +#: part/views.py:792 +msgid "Part was deleted" +msgstr "" + +#: part/views.py:801 +msgid "Part Pricing" +msgstr "" + +#: part/views.py:950 +msgid "Create Part Parameter Template" +msgstr "" + +#: part/views.py:960 +msgid "Edit Part Parameter Template" +msgstr "" + +#: part/views.py:967 +msgid "Delete Part Parameter Template" +msgstr "" + +#: part/views.py:1010 templates/js/translated/part.js:317 +msgid "Edit Part Category" +msgstr "" + +#: part/views.py:1048 +msgid "Delete Part Category" +msgstr "" + +#: part/views.py:1054 +msgid "Part category was deleted" +msgstr "" + +#: part/views.py:1063 +msgid "Create Category Parameter Template" +msgstr "" + +#: part/views.py:1164 +msgid "Edit Category Parameter Template" +msgstr "" + +#: part/views.py:1220 +msgid "Delete Category Parameter Template" +msgstr "" + +#: part/views.py:1242 +msgid "Added new price break" +msgstr "" + +#: part/views.py:1318 +msgid "Edit Internal Price Break" +msgstr "" + +#: part/views.py:1326 +msgid "Delete Internal Price Break" +msgstr "" + +#: plugin/apps.py:52 +msgid "Your enviroment has an outdated git version. This prevents InvenTree from loading plugin details." +msgstr "" + +#: plugin/events.py:225 +msgid "Label printing failed" +msgstr "" + +#: plugin/integration.py:146 +msgid "No author found" +msgstr "" + +#: plugin/integration.py:160 +msgid "No date found" +msgstr "" + +#: plugin/models.py:26 +msgid "Plugin Configuration" +msgstr "" + +#: plugin/models.py:27 +msgid "Plugin Configurations" +msgstr "" + +#: plugin/models.py:32 +msgid "Key" +msgstr "" + +#: plugin/models.py:33 +msgid "Key of plugin" +msgstr "" + +#: plugin/models.py:41 +msgid "PluginName of the plugin" +msgstr "" + +#: plugin/models.py:47 +msgid "Is the plugin active" +msgstr "" + +#: plugin/models.py:182 +msgid "Plugin" +msgstr "" + +#: plugin/samples/integration/sample.py:42 +msgid "Enable PO" +msgstr "" + +#: plugin/samples/integration/sample.py:43 +msgid "Enable PO functionality in InvenTree interface" +msgstr "" + +#: plugin/samples/integration/sample.py:48 +msgid "API Key" +msgstr "" + +#: plugin/samples/integration/sample.py:49 +msgid "Key required for accessing external API" +msgstr "" + +#: plugin/samples/integration/sample.py:52 +msgid "Numerical" +msgstr "" + +#: plugin/samples/integration/sample.py:53 +msgid "A numerical setting" +msgstr "" + +#: plugin/samples/integration/sample.py:58 +msgid "Choice Setting" +msgstr "" + +#: plugin/samples/integration/sample.py:59 +msgid "A setting with multiple choices" +msgstr "" + +#: plugin/serializers.py:49 +msgid "Source URL" +msgstr "" + +#: plugin/serializers.py:50 +msgid "Source for the package - this can be a custom registry or a VCS path" +msgstr "" + +#: plugin/serializers.py:55 +msgid "Package Name" +msgstr "" + +#: plugin/serializers.py:56 +msgid "Name for the Plugin Package - can also contain a version indicator" +msgstr "" + +#: plugin/serializers.py:59 +msgid "Confirm plugin installation" +msgstr "" + +#: plugin/serializers.py:60 +msgid "This will install this plugin now into the current instance. The instance will go into maintenance." +msgstr "" + +#: plugin/serializers.py:75 +msgid "Installation not confirmed" +msgstr "" + +#: plugin/serializers.py:77 +msgid "Either packagename of URL must be provided" +msgstr "" + +#: report/api.py:235 report/api.py:282 +#, python-brace-format +msgid "Template file '{template}' is missing or does not exist" +msgstr "" + +#: report/models.py:178 +msgid "Template name" +msgstr "" + +#: report/models.py:184 +msgid "Report template file" +msgstr "" + +#: report/models.py:191 +msgid "Report template description" +msgstr "" + +#: report/models.py:197 +msgid "Report revision number (auto-increments)" +msgstr "" + +#: report/models.py:288 +msgid "Pattern for generating report filenames" +msgstr "" + +#: report/models.py:295 +msgid "Report template is enabled" +msgstr "" + +#: report/models.py:319 +msgid "StockItem query filters (comma-separated list of key=value pairs)" +msgstr "" + +#: report/models.py:327 +msgid "Include Installed Tests" +msgstr "" + +#: report/models.py:328 +msgid "Include test results for stock items installed inside assembled item" +msgstr "" + +#: report/models.py:378 +msgid "Build Filters" +msgstr "" + +#: report/models.py:379 +msgid "Build query filters (comma-separated list of key=value pairs" +msgstr "" + +#: report/models.py:421 +msgid "Part Filters" +msgstr "" + +#: report/models.py:422 +msgid "Part query filters (comma-separated list of key=value pairs" +msgstr "" + +#: report/models.py:456 +msgid "Purchase order query filters" +msgstr "" + +#: report/models.py:494 +msgid "Sales order query filters" +msgstr "" + +#: report/models.py:548 +msgid "Snippet" +msgstr "" + +#: report/models.py:549 +msgid "Report snippet file" +msgstr "" + +#: report/models.py:553 +msgid "Snippet file description" +msgstr "" + +#: report/models.py:588 +msgid "Asset" +msgstr "" + +#: report/models.py:589 +msgid "Report asset file" +msgstr "" + +#: report/models.py:592 +msgid "Asset file description" +msgstr "" + +#: report/templates/report/inventree_build_order_base.html:147 +msgid "Required For" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:21 +msgid "Stock Item Test Report" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:79 +#: stock/models.py:629 stock/templates/stock/item_base.html:156 +#: templates/js/translated/build.js:374 templates/js/translated/build.js:522 +#: templates/js/translated/build.js:920 templates/js/translated/build.js:1309 +#: templates/js/translated/model_renderers.js:106 +#: templates/js/translated/order.js:99 templates/js/translated/order.js:2142 +#: templates/js/translated/order.js:2231 templates/js/translated/stock.js:434 +msgid "Serial Number" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:88 +msgid "Test Results" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:93 +#: stock/models.py:2152 +msgid "Test" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:94 +#: stock/models.py:2158 +msgid "Result" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:97 +#: templates/InvenTree/settings/plugin.html:51 +#: templates/InvenTree/settings/plugin_settings.html:38 +#: templates/js/translated/order.js:984 templates/js/translated/stock.js:2344 +msgid "Date" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:108 +msgid "Pass" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:110 +msgid "Fail" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:123 +#: stock/templates/stock/stock_sidebar.html:16 +msgid "Installed Items" +msgstr "" + +#: report/templates/report/inventree_test_report_base.html:137 +#: templates/js/translated/stock.js:554 templates/js/translated/stock.js:724 +#: templates/js/translated/stock.js:2593 +msgid "Serial" +msgstr "" + +#: stock/api.py:543 +msgid "Quantity is required" +msgstr "" + +#: stock/api.py:550 +msgid "Valid part must be supplied" +msgstr "" + +#: stock/api.py:575 +msgid "Serial numbers cannot be supplied for a non-trackable part" +msgstr "" + +#: stock/forms.py:74 stock/forms.py:198 stock/models.py:686 +#: stock/templates/stock/item_base.html:193 +#: templates/js/translated/stock.js:1821 +msgid "Expiry Date" +msgstr "" + +#: stock/forms.py:75 stock/forms.py:199 +msgid "Expiration date for this stock item" +msgstr "" + +#: stock/forms.py:78 +msgid "Enter unique serial numbers (or leave blank)" +msgstr "" + +#: stock/forms.py:133 +msgid "Destination for serialized stock (by default, will remain in current location)" +msgstr "" + +#: stock/forms.py:135 +msgid "Serial numbers" +msgstr "" + +#: stock/forms.py:135 +msgid "Unique serial numbers (must match quantity)" +msgstr "" + +#: stock/forms.py:137 stock/forms.py:171 +msgid "Add transaction note (optional)" +msgstr "" + +#: stock/forms.py:169 +msgid "Destination location for uninstalled items" +msgstr "" + +#: stock/forms.py:173 +msgid "Confirm uninstall" +msgstr "" + +#: stock/forms.py:173 +msgid "Confirm removal of installed stock items" +msgstr "" + +#: stock/models.py:91 stock/models.py:723 +#: stock/templates/stock/item_base.html:407 +msgid "Owner" +msgstr "" + +#: stock/models.py:92 stock/models.py:724 +msgid "Select Owner" +msgstr "" + +#: stock/models.py:442 +msgid "StockItem with this serial number already exists" +msgstr "" + +#: stock/models.py:484 +#, python-brace-format +msgid "Part type ('{pf}') must be {pe}" +msgstr "" + +#: stock/models.py:494 stock/models.py:503 +msgid "Quantity must be 1 for item with a serial number" +msgstr "" + +#: stock/models.py:495 +msgid "Serial number cannot be set if quantity greater than 1" +msgstr "" + +#: stock/models.py:517 +msgid "Item cannot belong to itself" +msgstr "" + +#: stock/models.py:523 +msgid "Item must have a build reference if is_building=True" +msgstr "" + +#: stock/models.py:530 +msgid "Build reference does not point to the same part object" +msgstr "" + +#: stock/models.py:573 +msgid "Parent Stock Item" +msgstr "" + +#: stock/models.py:582 +msgid "Base part" +msgstr "" + +#: stock/models.py:590 +msgid "Select a matching supplier part for this stock item" +msgstr "" + +#: stock/models.py:596 stock/templates/stock/location.html:16 +#: stock/templates/stock/stock_app_base.html:8 +msgid "Stock Location" +msgstr "" + +#: stock/models.py:599 +msgid "Where is this stock item located?" +msgstr "" + +#: stock/models.py:606 +msgid "Packaging this stock item is stored in" +msgstr "" + +#: stock/models.py:612 stock/templates/stock/item_base.html:282 +msgid "Installed In" +msgstr "" + +#: stock/models.py:615 +msgid "Is this item installed in another item?" +msgstr "" + +#: stock/models.py:631 +msgid "Serial number for this item" +msgstr "" + +#: stock/models.py:645 +msgid "Batch code for this stock item" +msgstr "" + +#: stock/models.py:649 +msgid "Stock Quantity" +msgstr "" + +#: stock/models.py:658 +msgid "Source Build" +msgstr "" + +#: stock/models.py:660 +msgid "Build for this stock item" +msgstr "" + +#: stock/models.py:671 +msgid "Source Purchase Order" +msgstr "" + +#: stock/models.py:674 +msgid "Purchase order for this stock item" +msgstr "" + +#: stock/models.py:680 +msgid "Destination Sales Order" +msgstr "" + +#: stock/models.py:687 +msgid "Expiry date for stock item. Stock will be considered expired after this date" +msgstr "" + +#: stock/models.py:700 +msgid "Delete on deplete" +msgstr "" + +#: stock/models.py:700 +msgid "Delete this Stock Item when stock is depleted" +msgstr "" + +#: stock/models.py:710 stock/templates/stock/item.html:137 +msgid "Stock Item Notes" +msgstr "" + +#: stock/models.py:719 +msgid "Single unit purchase price at time of purchase" +msgstr "" + +#: stock/models.py:751 +msgid "Converted to part" +msgstr "" + +#: stock/models.py:1271 +msgid "Part is not set as trackable" +msgstr "" + +#: stock/models.py:1277 +msgid "Quantity must be integer" +msgstr "" + +#: stock/models.py:1283 +#, python-brace-format +msgid "Quantity must not exceed available stock quantity ({n})" +msgstr "" + +#: stock/models.py:1286 +msgid "Serial numbers must be a list of integers" +msgstr "" + +#: stock/models.py:1289 +msgid "Quantity does not match serial numbers" +msgstr "" + +#: stock/models.py:1296 +#, python-brace-format +msgid "Serial numbers already exist: {exists}" +msgstr "" + +#: stock/models.py:1367 +msgid "Stock item has been assigned to a sales order" +msgstr "" + +#: stock/models.py:1370 +msgid "Stock item is installed in another item" +msgstr "" + +#: stock/models.py:1373 +msgid "Stock item contains other items" +msgstr "" + +#: stock/models.py:1376 +msgid "Stock item has been assigned to a customer" +msgstr "" + +#: stock/models.py:1379 +msgid "Stock item is currently in production" +msgstr "" + +#: stock/models.py:1382 +msgid "Serialized stock cannot be merged" +msgstr "" + +#: stock/models.py:1389 stock/serializers.py:832 +msgid "Duplicate stock items" +msgstr "" + +#: stock/models.py:1393 +msgid "Stock items must refer to the same part" +msgstr "" + +#: stock/models.py:1397 +msgid "Stock items must refer to the same supplier part" +msgstr "" + +#: stock/models.py:1401 +msgid "Stock status codes must match" +msgstr "" + +#: stock/models.py:1573 +msgid "StockItem cannot be moved as it is not in stock" +msgstr "" + +#: stock/models.py:2072 +msgid "Entry notes" +msgstr "" + +#: stock/models.py:2129 +msgid "Value must be provided for this test" +msgstr "" + +#: stock/models.py:2135 +msgid "Attachment must be uploaded for this test" +msgstr "" + +#: stock/models.py:2153 +msgid "Test name" +msgstr "" + +#: stock/models.py:2159 +msgid "Test result" +msgstr "" + +#: stock/models.py:2165 +msgid "Test output value" +msgstr "" + +#: stock/models.py:2172 +msgid "Test result attachment" +msgstr "" + +#: stock/models.py:2178 +msgid "Test notes" +msgstr "" + +#: stock/serializers.py:173 +msgid "Purchase price of this stock item" +msgstr "" + +#: stock/serializers.py:180 +msgid "Purchase currency of this stock item" +msgstr "" + +#: stock/serializers.py:294 +msgid "Enter number of stock items to serialize" +msgstr "" + +#: stock/serializers.py:309 +#, python-brace-format +msgid "Quantity must not exceed available stock quantity ({q})" +msgstr "" + +#: stock/serializers.py:315 +msgid "Enter serial numbers for new items" +msgstr "" + +#: stock/serializers.py:326 stock/serializers.py:789 stock/serializers.py:1030 +msgid "Destination stock location" +msgstr "" + +#: stock/serializers.py:333 +msgid "Optional note field" +msgstr "" + +#: stock/serializers.py:346 +msgid "Serial numbers cannot be assigned to this part" +msgstr "" + +#: stock/serializers.py:363 stock/views.py:1019 +msgid "Serial numbers already exist" +msgstr "" + +#: stock/serializers.py:405 +msgid "Select stock item to install" +msgstr "" + +#: stock/serializers.py:421 +msgid "Stock item is unavailable" +msgstr "" + +#: stock/serializers.py:428 +msgid "Selected part is not in the Bill of Materials" +msgstr "" + +#: stock/serializers.py:646 +msgid "Part must be salable" +msgstr "" + +#: stock/serializers.py:650 +msgid "Item is allocated to a sales order" +msgstr "" + +#: stock/serializers.py:654 +msgid "Item is allocated to a build order" +msgstr "" + +#: stock/serializers.py:684 +msgid "Customer to assign stock items" +msgstr "" + +#: stock/serializers.py:690 +msgid "Selected company is not a customer" +msgstr "" + +#: stock/serializers.py:698 +msgid "Stock assignment notes" +msgstr "" + +#: stock/serializers.py:708 stock/serializers.py:938 +msgid "A list of stock items must be provided" +msgstr "" + +#: stock/serializers.py:796 +msgid "Stock merging notes" +msgstr "" + +#: stock/serializers.py:801 +msgid "Allow mismatched suppliers" +msgstr "" + +#: stock/serializers.py:802 +msgid "Allow stock items with different supplier parts to be merged" +msgstr "" + +#: stock/serializers.py:807 +msgid "Allow mismatched status" +msgstr "" + +#: stock/serializers.py:808 +msgid "Allow stock items with different status codes to be merged" +msgstr "" + +#: stock/serializers.py:818 +msgid "At least two stock items must be provided" +msgstr "" + +#: stock/serializers.py:900 +msgid "StockItem primary key value" +msgstr "" + +#: stock/serializers.py:928 +msgid "Stock transaction notes" +msgstr "" + +#: stock/templates/stock/item.html:17 +msgid "Stock Tracking Information" +msgstr "" + +#: stock/templates/stock/item.html:22 +msgid "New Entry" +msgstr "" + +#: stock/templates/stock/item.html:74 +msgid "Child Stock Items" +msgstr "" + +#: stock/templates/stock/item.html:82 +msgid "This stock item does not have any child items" +msgstr "" + +#: stock/templates/stock/item.html:91 +#: stock/templates/stock/stock_sidebar.html:12 +msgid "Test Data" +msgstr "" + +#: stock/templates/stock/item.html:95 stock/templates/stock/item_base.html:60 +msgid "Test Report" +msgstr "" + +#: stock/templates/stock/item.html:99 +msgid "Delete Test Data" +msgstr "" + +#: stock/templates/stock/item.html:103 +msgid "Add Test Data" +msgstr "" + +#: stock/templates/stock/item.html:152 +msgid "Installed Stock Items" +msgstr "" + +#: stock/templates/stock/item.html:156 templates/js/translated/stock.js:2703 +msgid "Install Stock Item" +msgstr "" + +#: stock/templates/stock/item.html:316 templates/js/translated/stock.js:1464 +msgid "Add Test Result" +msgstr "" + +#: stock/templates/stock/item_base.html:42 +#: templates/js/translated/barcode.js:330 +#: templates/js/translated/barcode.js:335 +msgid "Unlink Barcode" +msgstr "" + +#: stock/templates/stock/item_base.html:44 +msgid "Link Barcode" +msgstr "" + +#: stock/templates/stock/item_base.html:46 templates/stock_table.html:21 +msgid "Scan to Location" +msgstr "" + +#: stock/templates/stock/item_base.html:54 +msgid "Printing actions" +msgstr "" + +#: stock/templates/stock/item_base.html:70 +msgid "Stock adjustment actions" +msgstr "" + +#: stock/templates/stock/item_base.html:74 +#: stock/templates/stock/location.html:54 templates/stock_table.html:47 +msgid "Count stock" +msgstr "" + +#: stock/templates/stock/item_base.html:77 templates/stock_table.html:45 +msgid "Add stock" +msgstr "" + +#: stock/templates/stock/item_base.html:80 templates/stock_table.html:46 +msgid "Remove stock" +msgstr "" + +#: stock/templates/stock/item_base.html:83 +msgid "Serialize stock" +msgstr "" + +#: stock/templates/stock/item_base.html:87 +#: stock/templates/stock/location.html:60 templates/stock_table.html:48 +msgid "Transfer stock" +msgstr "" + +#: stock/templates/stock/item_base.html:90 templates/stock_table.html:51 +msgid "Assign to customer" +msgstr "" + +#: stock/templates/stock/item_base.html:93 +msgid "Return to stock" +msgstr "" + +#: stock/templates/stock/item_base.html:96 +msgid "Uninstall stock item" +msgstr "" + +#: stock/templates/stock/item_base.html:96 +msgid "Uninstall" +msgstr "" + +#: stock/templates/stock/item_base.html:100 +msgid "Install stock item" +msgstr "" + +#: stock/templates/stock/item_base.html:100 +msgid "Install" +msgstr "" + +#: stock/templates/stock/item_base.html:115 +msgid "Convert to variant" +msgstr "" + +#: stock/templates/stock/item_base.html:118 +msgid "Duplicate stock item" +msgstr "" + +#: stock/templates/stock/item_base.html:120 +msgid "Edit stock item" +msgstr "" + +#: stock/templates/stock/item_base.html:123 +msgid "Delete stock item" +msgstr "" + +#: stock/templates/stock/item_base.html:161 +msgid "previous page" +msgstr "" + +#: stock/templates/stock/item_base.html:161 +msgid "Navigate to previous serial number" +msgstr "" + +#: stock/templates/stock/item_base.html:170 +msgid "next page" +msgstr "" + +#: stock/templates/stock/item_base.html:170 +msgid "Navigate to next serial number" +msgstr "" + +#: stock/templates/stock/item_base.html:197 +#, python-format +msgid "This StockItem expired on %(item.expiry_date)s" +msgstr "" + +#: stock/templates/stock/item_base.html:197 +#: templates/js/translated/table_filters.js:261 +msgid "Expired" +msgstr "" + +#: stock/templates/stock/item_base.html:199 +#, python-format +msgid "This StockItem expires on %(item.expiry_date)s" +msgstr "" + +#: stock/templates/stock/item_base.html:199 +#: templates/js/translated/table_filters.js:267 +msgid "Stale" +msgstr "" + +#: stock/templates/stock/item_base.html:206 +#: templates/js/translated/stock.js:1837 +msgid "Last Updated" +msgstr "" + +#: stock/templates/stock/item_base.html:211 +msgid "Last Stocktake" +msgstr "" + +#: stock/templates/stock/item_base.html:215 +msgid "No stocktake performed" +msgstr "" + +#: stock/templates/stock/item_base.html:224 +msgid "This stock item is in production and cannot be edited." +msgstr "" + +#: stock/templates/stock/item_base.html:225 +msgid "Edit the stock item from the build view." +msgstr "" + +#: stock/templates/stock/item_base.html:238 +msgid "This stock item has not passed all required tests" +msgstr "" + +#: stock/templates/stock/item_base.html:246 +msgid "This stock item is allocated to Sales Order" +msgstr "" + +#: stock/templates/stock/item_base.html:254 +msgid "This stock item is allocated to Build Order" +msgstr "" + +#: stock/templates/stock/item_base.html:260 +msgid "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." +msgstr "" + +#: stock/templates/stock/item_base.html:301 +#: templates/js/translated/build.js:1331 +msgid "No location set" +msgstr "" + +#: stock/templates/stock/item_base.html:308 +msgid "Barcode Identifier" +msgstr "" + +#: stock/templates/stock/item_base.html:350 +msgid "Parent Item" +msgstr "" + +#: stock/templates/stock/item_base.html:368 +msgid "No manufacturer set" +msgstr "" + +#: stock/templates/stock/item_base.html:393 +msgid "Tests" +msgstr "" + +#: stock/templates/stock/item_base.html:411 +msgid "You are not in the list of owners of this item. This stock item cannot be edited." +msgstr "" + +#: stock/templates/stock/item_base.html:412 +#: stock/templates/stock/location.html:118 +msgid "Read only" +msgstr "" + +#: stock/templates/stock/item_base.html:486 +msgid "Edit Stock Status" +msgstr "" + +#: stock/templates/stock/item_delete.html:9 +msgid "Are you sure you want to delete this stock item?" +msgstr "" + +#: stock/templates/stock/item_delete.html:12 +#, python-format +msgid "This will remove %(qty)s units of %(full_name)s from stock." +msgstr "" + +#: stock/templates/stock/item_serialize.html:5 +msgid "Create serialized items from this stock item." +msgstr "" + +#: stock/templates/stock/item_serialize.html:7 +msgid "Select quantity to serialize, and unique serial numbers." +msgstr "" + +#: stock/templates/stock/location.html:40 +msgid "Check-in Items" +msgstr "" + +#: stock/templates/stock/location.html:68 +msgid "Location actions" +msgstr "" + +#: stock/templates/stock/location.html:70 +msgid "Edit location" +msgstr "" + +#: stock/templates/stock/location.html:72 +msgid "Delete location" +msgstr "" + +#: stock/templates/stock/location.html:81 +msgid "Create new stock location" +msgstr "" + +#: stock/templates/stock/location.html:82 +msgid "New Location" +msgstr "" + +#: stock/templates/stock/location.html:100 +#: stock/templates/stock/location.html:106 +msgid "Location Path" +msgstr "" + +#: stock/templates/stock/location.html:107 +msgid "Top level stock location" +msgstr "" + +#: stock/templates/stock/location.html:113 +msgid "Location Owner" +msgstr "" + +#: stock/templates/stock/location.html:117 +msgid "You are not in the list of owners of this location. This stock location cannot be edited." +msgstr "" + +#: stock/templates/stock/location.html:133 +#: stock/templates/stock/location.html:180 +#: stock/templates/stock/location_sidebar.html:5 +msgid "Sublocations" +msgstr "" + +#: stock/templates/stock/location.html:147 templates/InvenTree/search.html:164 +#: templates/js/translated/search.js:145 templates/stats.html:109 +#: users/models.py:42 +msgid "Stock Locations" +msgstr "" + +#: stock/templates/stock/location_delete.html:8 +msgid "Are you sure you want to delete this stock location?" +msgstr "" + +#: stock/templates/stock/location_delete.html:13 +#, python-format +msgid "This location contains %(n)s child locations" +msgstr "" + +#: stock/templates/stock/location_delete.html:15 +#, python-format +msgid "If this location is deleted, these child locations will be moved to %(location)s" +msgstr "" + +#: stock/templates/stock/location_delete.html:17 +msgid "If this location is deleted, these child locations will be moved to the top level stock location" +msgstr "" + +#: stock/templates/stock/location_delete.html:25 +#, python-format +msgid "This location contains %(n)s stock items" +msgstr "" + +#: stock/templates/stock/location_delete.html:27 +#, python-format +msgid "If this location is deleted, these stock items will be moved to %(location)s" +msgstr "" + +#: stock/templates/stock/location_delete.html:29 +msgid "If this location is deleted, these stock items will be moved to the top level stock location" +msgstr "" + +#: stock/templates/stock/stock_app_base.html:16 +msgid "Loading..." +msgstr "" + +#: stock/templates/stock/stock_sidebar.html:5 +msgid "Stock Tracking" +msgstr "" + +#: stock/templates/stock/stock_sidebar.html:8 +msgid "Allocations" +msgstr "" + +#: stock/templates/stock/stock_sidebar.html:20 +msgid "Child Items" +msgstr "" + +#: stock/templates/stock/stock_uninstall.html:8 +msgid "The following stock items will be uninstalled" +msgstr "" + +#: stock/templates/stock/stockitem_convert.html:7 stock/views.py:631 +msgid "Convert Stock Item" +msgstr "" + +#: stock/templates/stock/stockitem_convert.html:8 +#, python-format +msgid "This stock item is current an instance of %(part)s" +msgstr "" + +#: stock/templates/stock/stockitem_convert.html:9 +msgid "It can be converted to one of the part variants listed below." +msgstr "" + +#: stock/templates/stock/stockitem_convert.html:14 +msgid "This action cannot be easily undone" +msgstr "" + +#: stock/templates/stock/tracking_delete.html:6 +msgid "Are you sure you want to delete this stock tracking entry?" +msgstr "" + +#: stock/views.py:152 templates/js/translated/stock.js:138 +msgid "Edit Stock Location" +msgstr "" + +#: stock/views.py:259 stock/views.py:610 stock/views.py:746 stock/views.py:1028 +msgid "Owner is required (ownership control is enabled)" +msgstr "" + +#: stock/views.py:274 +msgid "Stock Location QR code" +msgstr "" + +#: stock/views.py:293 +msgid "Return to Stock" +msgstr "" + +#: stock/views.py:302 +msgid "Specify a valid location" +msgstr "" + +#: stock/views.py:313 +msgid "Stock item returned from customer" +msgstr "" + +#: stock/views.py:324 +msgid "Delete All Test Data" +msgstr "" + +#: stock/views.py:341 +msgid "Confirm test data deletion" +msgstr "" + +#: stock/views.py:342 +msgid "Check the confirmation box" +msgstr "" + +#: stock/views.py:357 +msgid "Stock Item QR Code" +msgstr "" + +#: stock/views.py:382 +msgid "Uninstall Stock Items" +msgstr "" + +#: stock/views.py:479 templates/js/translated/stock.js:1046 +msgid "Confirm stock adjustment" +msgstr "" + +#: stock/views.py:490 +msgid "Uninstalled stock items" +msgstr "" + +#: stock/views.py:512 templates/js/translated/stock.js:343 +msgid "Edit Stock Item" +msgstr "" + +#: stock/views.py:672 +msgid "Create new Stock Location" +msgstr "" + +#: stock/views.py:773 +msgid "Create new Stock Item" +msgstr "" + +#: stock/views.py:915 templates/js/translated/stock.js:323 +msgid "Duplicate Stock Item" +msgstr "" + +#: stock/views.py:997 +msgid "Quantity cannot be negative" +msgstr "" + +#: stock/views.py:1097 +msgid "Delete Stock Location" +msgstr "" + +#: stock/views.py:1110 +msgid "Delete Stock Item" +msgstr "" + +#: stock/views.py:1121 +msgid "Delete Stock Tracking Entry" +msgstr "" + +#: stock/views.py:1128 +msgid "Edit Stock Tracking Entry" +msgstr "" + +#: stock/views.py:1137 +msgid "Add Stock Tracking Entry" +msgstr "" + +#: templates/403.html:5 templates/403.html:11 +msgid "Permission Denied" +msgstr "" + +#: templates/403.html:14 +msgid "You do not have permission to view this page." +msgstr "" + +#: templates/404.html:5 templates/404.html:11 +msgid "Page Not Found" +msgstr "" + +#: templates/404.html:14 +msgid "The requested page does not exist" +msgstr "" + +#: templates/500.html:5 templates/500.html:11 +msgid "Internal Server Error" +msgstr "" + +#: templates/500.html:14 +msgid "The InvenTree server raised an internal error" +msgstr "" + +#: templates/500.html:15 +msgid "Refer to the error log in the admin interface for further details" +msgstr "" + +#: templates/503.html:10 templates/503.html:35 +msgid "Site is in Maintenance" +msgstr "" + +#: templates/503.html:41 +msgid "The site is currently in maintenance and should be up again soon!" +msgstr "" + +#: templates/InvenTree/index.html:7 +msgid "Index" +msgstr "" + +#: templates/InvenTree/index.html:88 +msgid "Subscribed Parts" +msgstr "" + +#: templates/InvenTree/index.html:98 +msgid "Subscribed Categories" +msgstr "" + +#: templates/InvenTree/index.html:108 +msgid "Latest Parts" +msgstr "" + +#: templates/InvenTree/index.html:119 +msgid "BOM Waiting Validation" +msgstr "" + +#: templates/InvenTree/index.html:145 +msgid "Recently Updated" +msgstr "" + +#: templates/InvenTree/index.html:168 +msgid "Depleted Stock" +msgstr "" + +#: templates/InvenTree/index.html:191 +msgid "Expired Stock" +msgstr "" + +#: templates/InvenTree/index.html:202 +msgid "Stale Stock" +msgstr "" + +#: templates/InvenTree/index.html:224 +msgid "Build Orders In Progress" +msgstr "" + +#: templates/InvenTree/index.html:235 +msgid "Overdue Build Orders" +msgstr "" + +#: templates/InvenTree/index.html:255 +msgid "Outstanding Purchase Orders" +msgstr "" + +#: templates/InvenTree/index.html:266 +msgid "Overdue Purchase Orders" +msgstr "" + +#: templates/InvenTree/index.html:286 +msgid "Outstanding Sales Orders" +msgstr "" + +#: templates/InvenTree/index.html:297 +msgid "Overdue Sales Orders" +msgstr "" + +#: templates/InvenTree/notifications/history.html:9 +msgid "Notification History" +msgstr "" + +#: templates/InvenTree/notifications/history.html:13 +#: templates/InvenTree/notifications/history.html:14 +msgid "Refresh Notification History" +msgstr "" + +#: templates/InvenTree/notifications/inbox.html:9 +msgid "Pending Notifications" +msgstr "" + +#: templates/InvenTree/notifications/inbox.html:13 +#: templates/InvenTree/notifications/inbox.html:14 +msgid "Mark all as read" +msgstr "" + +#: templates/InvenTree/notifications/inbox.html:16 +#: templates/InvenTree/notifications/inbox.html:17 +msgid "Refresh Pending Notifications" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:10 +#: templates/InvenTree/notifications/sidebar.html:5 +#: templates/InvenTree/settings/sidebar.html:17 templates/notifications.html:5 +msgid "Notifications" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:51 +#: templates/InvenTree/settings/settings.html:314 +msgid "ID" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:57 +msgid "Age" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:88 +#: templates/InvenTree/settings/plugin.html:133 +msgid "Message" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:94 +#: templates/InvenTree/notifications/notifications.html:150 +msgid "Delete Notification" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:116 +msgid "No unread notifications found" +msgstr "" + +#: templates/InvenTree/notifications/notifications.html:140 +msgid "No notification history found" +msgstr "" + +#: templates/InvenTree/notifications/sidebar.html:8 +msgid "Inbox" +msgstr "" + +#: templates/InvenTree/notifications/sidebar.html:10 +msgid "History" +msgstr "" + +#: templates/InvenTree/search.html:8 +msgid "Search Results" +msgstr "" + +#: templates/InvenTree/settings/barcode.html:8 +msgid "Barcode Settings" +msgstr "" + +#: templates/InvenTree/settings/build.html:8 +msgid "Build Order Settings" +msgstr "" + +#: templates/InvenTree/settings/category.html:7 +msgid "Category Settings" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:8 +msgid "Currency Settings" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:19 +msgid "Base Currency" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:24 +msgid "Exchange Rates" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:38 +msgid "Last Update" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:44 +msgid "Never" +msgstr "" + +#: templates/InvenTree/settings/currencies.html:49 +msgid "Update Now" +msgstr "" + +#: templates/InvenTree/settings/global.html:9 +msgid "Server Settings" +msgstr "" + +#: templates/InvenTree/settings/login.html:9 +#: templates/InvenTree/settings/sidebar.html:31 +msgid "Login Settings" +msgstr "" + +#: templates/InvenTree/settings/login.html:21 templates/account/signup.html:5 +msgid "Signup" +msgstr "" + +#: templates/InvenTree/settings/mixins/settings.html:5 +#: templates/InvenTree/settings/settings.html:12 templates/navbar.html:131 +msgid "Settings" +msgstr "" + +#: templates/InvenTree/settings/mixins/urls.html:5 +msgid "URLs" +msgstr "" + +#: templates/InvenTree/settings/mixins/urls.html:8 +#, python-format +msgid "The Base-URL for this plugin is %(base)s." +msgstr "" + +#: templates/InvenTree/settings/mixins/urls.html:23 +msgid "Open in new tab" +msgstr "" + +#: templates/InvenTree/settings/part.html:7 +msgid "Part Settings" +msgstr "" + +#: templates/InvenTree/settings/part.html:44 +msgid "Part Import" +msgstr "" + +#: templates/InvenTree/settings/part.html:48 +msgid "Import Part" +msgstr "" + +#: templates/InvenTree/settings/part.html:62 +msgid "Part Parameter Templates" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:10 +msgid "Plugin Settings" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:16 +msgid "Changing the settings below require you to immediatly restart InvenTree. Do not change this while under active usage." +msgstr "" + +#: templates/InvenTree/settings/plugin.html:34 +msgid "Plugins" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:39 +#: templates/js/translated/plugin.js:15 +msgid "Install Plugin" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:48 templates/navbar.html:129 +#: users/models.py:39 +msgid "Admin" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:50 +#: templates/InvenTree/settings/plugin_settings.html:28 +msgid "Author" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:52 +#: templates/InvenTree/settings/plugin_settings.html:43 +msgid "Version" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:82 +msgid "code sample" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:99 +msgid "Inactive plugins" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:122 +msgid "Plugin Error Stack" +msgstr "" + +#: templates/InvenTree/settings/plugin.html:131 +msgid "Stage" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:10 +#, python-format +msgid "Plugin details for %(name)s" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:17 +msgid "Plugin information" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:48 +msgid "no version information supplied" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:62 +msgid "License" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:71 +msgid "The code information is pulled from the latest git commit for this plugin. It might not reflect official version numbers or information but the actual code running." +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:77 +msgid "Package information" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:83 +msgid "Installation method" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:86 +msgid "This plugin was installed as a package" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:88 +msgid "This plugin was found in a local InvenTree path" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:94 +msgid "Installation path" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:100 +msgid "Commit Author" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:104 +#: templates/about.html:47 +msgid "Commit Date" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:108 +#: templates/about.html:40 +msgid "Commit Hash" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:112 +msgid "Commit Message" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:117 +msgid "Sign Status" +msgstr "" + +#: templates/InvenTree/settings/plugin_settings.html:122 +msgid "Sign Key" +msgstr "" + +#: templates/InvenTree/settings/po.html:7 +msgid "Purchase Order Settings" +msgstr "" + +#: templates/InvenTree/settings/report.html:8 +#: templates/InvenTree/settings/user_reports.html:9 +msgid "Report Settings" +msgstr "" + +#: templates/InvenTree/settings/setting.html:37 +msgid "No value set" +msgstr "" + +#: templates/InvenTree/settings/setting.html:42 +msgid "Edit setting" +msgstr "" + +#: templates/InvenTree/settings/settings.html:116 +msgid "Edit Plugin Setting" +msgstr "" + +#: templates/InvenTree/settings/settings.html:118 +msgid "Edit Global Setting" +msgstr "" + +#: templates/InvenTree/settings/settings.html:120 +msgid "Edit User Setting" +msgstr "" + +#: templates/InvenTree/settings/settings.html:209 +msgid "No category parameter templates found" +msgstr "" + +#: templates/InvenTree/settings/settings.html:231 +#: templates/InvenTree/settings/settings.html:330 +msgid "Edit Template" +msgstr "" + +#: templates/InvenTree/settings/settings.html:232 +#: templates/InvenTree/settings/settings.html:331 +msgid "Delete Template" +msgstr "" + +#: templates/InvenTree/settings/settings.html:310 +msgid "No part parameter templates found" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:6 +#: templates/InvenTree/settings/user_settings.html:9 +msgid "User Settings" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:9 +#: templates/InvenTree/settings/user.html:12 +msgid "Account Settings" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:11 +#: templates/InvenTree/settings/user_display.html:9 +msgid "Display Settings" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:13 +msgid "Home Page" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:15 +#: templates/InvenTree/settings/user_search.html:9 +msgid "Search Settings" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:19 +msgid "Label Printing" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:21 +#: templates/InvenTree/settings/sidebar.html:37 +msgid "Reporting" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:26 +msgid "Global Settings" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:29 +msgid "Server Configuration" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:35 +msgid "Currencies" +msgstr "" + +#: templates/InvenTree/settings/sidebar.html:41 +msgid "Categories" +msgstr "" + +#: templates/InvenTree/settings/so.html:7 +msgid "Sales Order Settings" +msgstr "" + +#: templates/InvenTree/settings/stock.html:7 +msgid "Stock Settings" +msgstr "" + +#: templates/InvenTree/settings/user.html:18 +#: templates/account/password_reset_from_key.html:4 +#: templates/account/password_reset_from_key.html:7 +msgid "Change Password" +msgstr "" + +#: templates/InvenTree/settings/user.html:22 +#: templates/js/translated/helpers.js:27 templates/notes_buttons.html:3 +#: templates/notes_buttons.html:4 +msgid "Edit" +msgstr "" + +#: templates/InvenTree/settings/user.html:32 +msgid "Username" +msgstr "" + +#: templates/InvenTree/settings/user.html:36 +msgid "First Name" +msgstr "" + +#: templates/InvenTree/settings/user.html:40 +msgid "Last Name" +msgstr "" + +#: templates/InvenTree/settings/user.html:54 +msgid "The following email addresses are associated with your account:" +msgstr "" + +#: templates/InvenTree/settings/user.html:75 +msgid "Verified" +msgstr "" + +#: templates/InvenTree/settings/user.html:77 +msgid "Unverified" +msgstr "" + +#: templates/InvenTree/settings/user.html:79 +msgid "Primary" +msgstr "" + +#: templates/InvenTree/settings/user.html:85 +msgid "Make Primary" +msgstr "" + +#: templates/InvenTree/settings/user.html:86 +msgid "Re-send Verification" +msgstr "" + +#: templates/InvenTree/settings/user.html:87 +#: templates/InvenTree/settings/user.html:149 +msgid "Remove" +msgstr "" + +#: templates/InvenTree/settings/user.html:95 +#: templates/InvenTree/settings/user.html:201 +msgid "Warning:" +msgstr "" + +#: templates/InvenTree/settings/user.html:96 +msgid "You currently do not have any email address set up. You should really add an email address so you can receive notifications, reset your password, etc." +msgstr "" + +#: templates/InvenTree/settings/user.html:104 +msgid "Add Email Address" +msgstr "" + +#: templates/InvenTree/settings/user.html:109 +msgid "Add Email" +msgstr "" + +#: templates/InvenTree/settings/user.html:117 +msgid "Social Accounts" +msgstr "" + +#: templates/InvenTree/settings/user.html:122 +msgid "You can sign in to your account using any of the following third party accounts:" +msgstr "" + +#: templates/InvenTree/settings/user.html:157 +msgid "You currently have no social network accounts connected to this account." +msgstr "" + +#: templates/InvenTree/settings/user.html:162 +msgid "Add a 3rd Party Account" +msgstr "" + +#: templates/InvenTree/settings/user.html:172 +msgid "Multifactor" +msgstr "" + +#: templates/InvenTree/settings/user.html:177 +msgid "You have these factors available:" +msgstr "" + +#: templates/InvenTree/settings/user.html:187 +msgid "TOTP" +msgstr "" + +#: templates/InvenTree/settings/user.html:193 +msgid "Static" +msgstr "" + +#: templates/InvenTree/settings/user.html:202 +msgid "You currently do not have any factors set up." +msgstr "" + +#: templates/InvenTree/settings/user.html:209 +msgid "Change factors" +msgstr "" + +#: templates/InvenTree/settings/user.html:210 +msgid "Setup multifactor" +msgstr "" + +#: templates/InvenTree/settings/user.html:212 +msgid "Remove multifactor" +msgstr "" + +#: templates/InvenTree/settings/user.html:220 +msgid "Active Sessions" +msgstr "" + +#: templates/InvenTree/settings/user.html:226 +msgid "Log out active sessions (except this one)" +msgstr "" + +#: templates/InvenTree/settings/user.html:227 +msgid "Log Out Active Sessions" +msgstr "" + +#: templates/InvenTree/settings/user.html:236 +msgid "unknown on unknown" +msgstr "" + +#: templates/InvenTree/settings/user.html:237 +msgid "unknown" +msgstr "" + +#: templates/InvenTree/settings/user.html:241 +msgid "IP Address" +msgstr "" + +#: templates/InvenTree/settings/user.html:242 +msgid "Device" +msgstr "" + +#: templates/InvenTree/settings/user.html:243 +msgid "Last Activity" +msgstr "" + +#: templates/InvenTree/settings/user.html:252 +#, python-format +msgid "%(time)s ago (this session)" +msgstr "" + +#: templates/InvenTree/settings/user.html:254 +#, python-format +msgid "%(time)s ago" +msgstr "" + +#: templates/InvenTree/settings/user.html:266 +msgid "Do you really want to remove the selected email address?" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:27 +msgid "Theme Settings" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:37 +msgid "Select theme" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:48 +msgid "Set Theme" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:56 +msgid "Language Settings" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:65 +msgid "Select language" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:81 +#, python-format +msgid "%(lang_translated)s%% translated" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:83 +msgid "No translations available" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:90 +msgid "Set Language" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:93 +msgid "Some languages are not complete" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:95 +msgid "Show only sufficent" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:97 +msgid "and hidden." +msgstr "" + +#: templates/InvenTree/settings/user_display.html:97 +msgid "Show them too" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:103 +msgid "Help the translation efforts!" +msgstr "" + +#: templates/InvenTree/settings/user_display.html:104 +#, python-format +msgid "Native language translation of the InvenTree web application is community contributed via crowdin. Contributions are welcomed and encouraged." +msgstr "" + +#: templates/InvenTree/settings/user_homepage.html:9 +msgid "Home Page Settings" +msgstr "" + +#: templates/InvenTree/settings/user_labels.html:9 +msgid "Label Settings" +msgstr "" + +#: templates/InvenTree/settings/user_notifications.html:8 +msgid "Notification Settings" +msgstr "" + +#: templates/about.html:10 +msgid "InvenTree Version Information" +msgstr "" + +#: templates/about.html:11 templates/about.html:105 +#: templates/js/translated/bom.js:132 templates/js/translated/bom.js:620 +#: templates/js/translated/modals.js:53 templates/js/translated/modals.js:584 +#: templates/js/translated/modals.js:678 templates/js/translated/modals.js:986 +#: templates/modals.html:15 templates/modals.html:27 templates/modals.html:39 +#: templates/modals.html:50 +msgid "Close" +msgstr "" + +#: templates/about.html:20 +msgid "InvenTree Version" +msgstr "" + +#: templates/about.html:25 +msgid "Development Version" +msgstr "" + +#: templates/about.html:28 +msgid "Up to Date" +msgstr "" + +#: templates/about.html:30 +msgid "Update Available" +msgstr "" + +#: templates/about.html:53 +msgid "InvenTree Documentation" +msgstr "" + +#: templates/about.html:58 +msgid "API Version" +msgstr "" + +#: templates/about.html:63 +msgid "Python Version" +msgstr "" + +#: templates/about.html:68 +msgid "Django Version" +msgstr "" + +#: templates/about.html:73 +msgid "View Code on GitHub" +msgstr "" + +#: templates/about.html:78 +msgid "Credits" +msgstr "" + +#: templates/about.html:83 +msgid "Mobile App" +msgstr "" + +#: templates/about.html:88 +msgid "Submit Bug Report" +msgstr "" + +#: templates/about.html:95 templates/clip.html:4 +msgid "copy to clipboard" +msgstr "" + +#: templates/about.html:95 +msgid "copy version information" +msgstr "" + +#: templates/account/email_confirm.html:6 +#: templates/account/email_confirm.html:10 +msgid "Confirm Email Address" +msgstr "" + +#: templates/account/email_confirm.html:16 +#, python-format +msgid "Please confirm that %(email)s is an email address for user %(user_display)s." +msgstr "" + +#: templates/account/email_confirm.html:27 +#, python-format +msgid "This email confirmation link expired or is invalid. Please issue a new email confirmation request." +msgstr "" + +#: templates/account/login.html:6 templates/account/login.html:16 +#: templates/account/login.html:39 +msgid "Sign In" +msgstr "" + +#: templates/account/login.html:21 +#, python-format +msgid "" +"Please sign in with one\n" +"of your existing third party accounts or sign up\n" +"for a account and sign in below:" +msgstr "" + +#: templates/account/login.html:25 +#, python-format +msgid "" +"If you have not created an account yet, then please\n" +"sign up first." +msgstr "" + +#: templates/account/login.html:42 +msgid "Forgot Password?" +msgstr "" + +#: templates/account/login.html:47 +msgid "InvenTree demo instance" +msgstr "" + +#: templates/account/login.html:47 +msgid "Click here for login details" +msgstr "" + +#: templates/account/login.html:55 +msgid "or use SSO" +msgstr "" + +#: templates/account/logout.html:5 templates/account/logout.html:8 +#: templates/account/logout.html:20 +msgid "Sign Out" +msgstr "" + +#: templates/account/logout.html:10 +msgid "Are you sure you want to sign out?" +msgstr "" + +#: templates/account/logout.html:19 +msgid "Back to Site" +msgstr "" + +#: templates/account/password_reset.html:5 +#: templates/account/password_reset.html:12 +msgid "Password Reset" +msgstr "" + +#: templates/account/password_reset.html:18 +msgid "Forgotten your password? Enter your email address below, and we'll send you an email allowing you to reset it." +msgstr "" + +#: templates/account/password_reset.html:23 +msgid "Reset My Password" +msgstr "" + +#: templates/account/password_reset.html:27 templates/account/signup.html:36 +msgid "This function is currently disabled. Please contact an administrator." +msgstr "" + +#: templates/account/password_reset_from_key.html:7 +msgid "Bad Token" +msgstr "" + +#: templates/account/password_reset_from_key.html:11 +#, python-format +msgid "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." +msgstr "" + +#: templates/account/password_reset_from_key.html:18 +msgid "Change password" +msgstr "" + +#: templates/account/password_reset_from_key.html:22 +msgid "Your password is now changed." +msgstr "" + +#: templates/account/signup.html:11 templates/account/signup.html:22 +msgid "Sign Up" +msgstr "" + +#: templates/account/signup.html:13 +#, python-format +msgid "Already have an account? Then please sign in." +msgstr "" + +#: templates/account/signup.html:27 +msgid "Or use a SSO-provider for signup" +msgstr "" + +#: templates/admin_button.html:2 +msgid "View in administration panel" +msgstr "" + +#: templates/allauth_2fa/authenticate.html:5 +msgid "Two-Factor Authentication" +msgstr "" + +#: templates/allauth_2fa/authenticate.html:12 +msgid "Authenticate" +msgstr "" + +#: templates/allauth_2fa/backup_tokens.html:6 +msgid "Two-Factor Authentication Backup Tokens" +msgstr "" + +#: templates/allauth_2fa/backup_tokens.html:17 +msgid "Backup tokens have been generated, but are not revealed here for security reasons. Press the button below to generate new ones." +msgstr "" + +#: templates/allauth_2fa/backup_tokens.html:20 +msgid "No tokens. Press the button below to generate some." +msgstr "" + +#: templates/allauth_2fa/backup_tokens.html:27 +msgid "Generate backup tokens" +msgstr "" + +#: templates/allauth_2fa/backup_tokens.html:31 +#: templates/allauth_2fa/setup.html:40 +msgid "Back to settings" +msgstr "" + +#: templates/allauth_2fa/remove.html:6 +msgid "Disable Two-Factor Authentication" +msgstr "" + +#: templates/allauth_2fa/remove.html:9 +msgid "Are you sure?" +msgstr "" + +#: templates/allauth_2fa/remove.html:14 +msgid "Disable Two-Factor" +msgstr "" + +#: templates/allauth_2fa/setup.html:6 +msgid "Setup Two-Factor Authentication" +msgstr "" + +#: templates/allauth_2fa/setup.html:10 +msgid "Step 1" +msgstr "" + +#: templates/allauth_2fa/setup.html:14 +msgid "Scan the QR code below with a token generator of your choice (for instance Google Authenticator)." +msgstr "" + +#: templates/allauth_2fa/setup.html:23 +msgid "Step 2" +msgstr "" + +#: templates/allauth_2fa/setup.html:27 +msgid "Input a token generated by the app:" +msgstr "" + +#: templates/allauth_2fa/setup.html:35 +msgid "Verify" +msgstr "" + +#: templates/attachment_button.html:4 templates/js/translated/attachment.js:54 +msgid "Add Link" +msgstr "" + +#: templates/attachment_button.html:7 templates/js/translated/attachment.js:36 +msgid "Add Attachment" +msgstr "" + +#: templates/base.html:99 +msgid "Server Restart Required" +msgstr "" + +#: templates/base.html:102 +msgid "A configuration option has been changed which requires a server restart" +msgstr "" + +#: templates/base.html:102 +msgid "Contact your system administrator for further information" +msgstr "" + +#: templates/email/build_order_required_stock.html:7 +msgid "Stock is required for the following build order" +msgstr "" + +#: templates/email/build_order_required_stock.html:8 +#, python-format +msgid "Build order %(build)s - building %(quantity)s x %(part)s" +msgstr "" + +#: templates/email/build_order_required_stock.html:10 +msgid "Click on the following link to view this build order" +msgstr "" + +#: templates/email/build_order_required_stock.html:14 +msgid "The following parts are low on required stock" +msgstr "" + +#: templates/email/build_order_required_stock.html:18 +#: templates/js/translated/bom.js:1350 +msgid "Required Quantity" +msgstr "" + +#: templates/email/build_order_required_stock.html:19 +#: templates/email/low_stock_notification.html:18 +#: templates/js/translated/bom.js:802 templates/js/translated/build.js:1425 +#: templates/js/translated/build.js:2144 templates/js/translated/part.js:522 +#: templates/js/translated/part.js:525 +#: templates/js/translated/table_filters.js:178 +msgid "Available" +msgstr "" + +#: templates/email/build_order_required_stock.html:38 +#: templates/email/low_stock_notification.html:31 +msgid "You are receiving this email because you are subscribed to notifications for this part " +msgstr "" + +#: templates/email/email.html:35 +msgid "InvenTree version" +msgstr "" + +#: templates/email/low_stock_notification.html:9 +msgid "Click on the following link to view this part" +msgstr "" + +#: templates/email/low_stock_notification.html:19 +msgid "Minimum Quantity" +msgstr "" + +#: templates/image_download.html:8 +msgid "Specify URL for downloading image" +msgstr "" + +#: templates/image_download.html:11 +msgid "Must be a valid image URL" +msgstr "" + +#: templates/image_download.html:12 +msgid "Remote server must be accessible" +msgstr "" + +#: templates/image_download.html:13 +msgid "Remote image must not exceed maximum allowable file size" +msgstr "" + +#: templates/js/translated/api.js:190 templates/js/translated/modals.js:1056 +msgid "No Response" +msgstr "" + +#: templates/js/translated/api.js:191 templates/js/translated/modals.js:1057 +msgid "No response from the InvenTree server" +msgstr "" + +#: templates/js/translated/api.js:197 +msgid "Error 400: Bad request" +msgstr "" + +#: templates/js/translated/api.js:198 +msgid "API request returned error code 400" +msgstr "" + +#: templates/js/translated/api.js:202 templates/js/translated/modals.js:1066 +msgid "Error 401: Not Authenticated" +msgstr "" + +#: templates/js/translated/api.js:203 templates/js/translated/modals.js:1067 +msgid "Authentication credentials not supplied" +msgstr "" + +#: templates/js/translated/api.js:207 templates/js/translated/modals.js:1071 +msgid "Error 403: Permission Denied" +msgstr "" + +#: templates/js/translated/api.js:208 templates/js/translated/modals.js:1072 +msgid "You do not have the required permissions to access this function" +msgstr "" + +#: templates/js/translated/api.js:212 templates/js/translated/modals.js:1076 +msgid "Error 404: Resource Not Found" +msgstr "" + +#: templates/js/translated/api.js:213 templates/js/translated/modals.js:1077 +msgid "The requested resource could not be located on the server" +msgstr "" + +#: templates/js/translated/api.js:217 +msgid "Error 405: Method Not Allowed" +msgstr "" + +#: templates/js/translated/api.js:218 +msgid "HTTP method not allowed at URL" +msgstr "" + +#: templates/js/translated/api.js:222 templates/js/translated/modals.js:1081 +msgid "Error 408: Timeout" +msgstr "" + +#: templates/js/translated/api.js:223 templates/js/translated/modals.js:1082 +msgid "Connection timeout while requesting data from server" +msgstr "" + +#: templates/js/translated/api.js:226 +msgid "Unhandled Error Code" +msgstr "" + +#: templates/js/translated/api.js:227 +msgid "Error code" +msgstr "" + +#: templates/js/translated/attachment.js:78 +msgid "No attachments found" +msgstr "" + +#: templates/js/translated/attachment.js:100 +msgid "Edit Attachment" +msgstr "" + +#: templates/js/translated/attachment.js:110 +msgid "Confirm Delete" +msgstr "" + +#: templates/js/translated/attachment.js:111 +msgid "Delete Attachment" +msgstr "" + +#: templates/js/translated/attachment.js:167 +msgid "Upload Date" +msgstr "" + +#: templates/js/translated/attachment.js:183 +msgid "Edit attachment" +msgstr "" + +#: templates/js/translated/attachment.js:190 +msgid "Delete attachment" +msgstr "" + +#: templates/js/translated/barcode.js:29 +msgid "Scan barcode data here using wedge scanner" +msgstr "" + +#: templates/js/translated/barcode.js:31 +msgid "Enter barcode data" +msgstr "" + +#: templates/js/translated/barcode.js:35 +msgid "Barcode" +msgstr "" + +#: templates/js/translated/barcode.js:53 +msgid "Enter optional notes for stock transfer" +msgstr "" + +#: templates/js/translated/barcode.js:54 +msgid "Enter notes" +msgstr "" + +#: templates/js/translated/barcode.js:92 +msgid "Server error" +msgstr "" + +#: templates/js/translated/barcode.js:113 +msgid "Unknown response from server" +msgstr "" + +#: templates/js/translated/barcode.js:140 +#: templates/js/translated/modals.js:1046 +msgid "Invalid server response" +msgstr "" + +#: templates/js/translated/barcode.js:233 +msgid "Scan barcode data below" +msgstr "" + +#: templates/js/translated/barcode.js:280 templates/navbar.html:101 +msgid "Scan Barcode" +msgstr "" + +#: templates/js/translated/barcode.js:291 +msgid "No URL in response" +msgstr "" + +#: templates/js/translated/barcode.js:309 +msgid "Link Barcode to Stock Item" +msgstr "" + +#: templates/js/translated/barcode.js:332 +msgid "This will remove the association between this stock item and the barcode" +msgstr "" + +#: templates/js/translated/barcode.js:338 +msgid "Unlink" +msgstr "" + +#: templates/js/translated/barcode.js:403 templates/js/translated/stock.js:998 +msgid "Remove stock item" +msgstr "" + +#: templates/js/translated/barcode.js:445 +msgid "Check Stock Items into Location" +msgstr "" + +#: templates/js/translated/barcode.js:449 +#: templates/js/translated/barcode.js:581 +msgid "Check In" +msgstr "" + +#: templates/js/translated/barcode.js:480 +msgid "No barcode provided" +msgstr "" + +#: templates/js/translated/barcode.js:515 +msgid "Stock Item already scanned" +msgstr "" + +#: templates/js/translated/barcode.js:519 +msgid "Stock Item already in this location" +msgstr "" + +#: templates/js/translated/barcode.js:526 +msgid "Added stock item" +msgstr "" + +#: templates/js/translated/barcode.js:533 +msgid "Barcode does not match Stock Item" +msgstr "" + +#: templates/js/translated/barcode.js:576 +msgid "Check Into Location" +msgstr "" + +#: templates/js/translated/barcode.js:639 +msgid "Barcode does not match a valid location" +msgstr "" + +#: templates/js/translated/bom.js:75 +msgid "Display row data" +msgstr "" + +#: templates/js/translated/bom.js:131 +msgid "Row Data" +msgstr "" + +#: templates/js/translated/bom.js:249 +msgid "Download BOM Template" +msgstr "" + +#: templates/js/translated/bom.js:252 templates/js/translated/bom.js:286 +#: templates/js/translated/order.js:429 templates/js/translated/tables.js:53 +msgid "Format" +msgstr "" + +#: templates/js/translated/bom.js:253 templates/js/translated/bom.js:287 +#: templates/js/translated/order.js:430 +msgid "Select file format" +msgstr "" + +#: templates/js/translated/bom.js:294 +msgid "Cascading" +msgstr "" + +#: templates/js/translated/bom.js:295 +msgid "Download cascading / multi-level BOM" +msgstr "" + +#: templates/js/translated/bom.js:300 +msgid "Levels" +msgstr "" + +#: templates/js/translated/bom.js:301 +msgid "Select maximum number of BOM levels to export (0 = all levels)" +msgstr "" + +#: templates/js/translated/bom.js:307 +msgid "Include Parameter Data" +msgstr "" + +#: templates/js/translated/bom.js:308 +msgid "Include part parameter data in exported BOM" +msgstr "" + +#: templates/js/translated/bom.js:313 +msgid "Include Stock Data" +msgstr "" + +#: templates/js/translated/bom.js:314 +msgid "Include part stock data in exported BOM" +msgstr "" + +#: templates/js/translated/bom.js:319 +msgid "Include Manufacturer Data" +msgstr "" + +#: templates/js/translated/bom.js:320 +msgid "Include part manufacturer data in exported BOM" +msgstr "" + +#: templates/js/translated/bom.js:325 +msgid "Include Supplier Data" +msgstr "" + +#: templates/js/translated/bom.js:326 +msgid "Include part supplier data in exported BOM" +msgstr "" + +#: templates/js/translated/bom.js:509 +msgid "Remove substitute part" +msgstr "" + +#: templates/js/translated/bom.js:565 +msgid "Select and add a new substitute part using the input below" +msgstr "" + +#: templates/js/translated/bom.js:576 +msgid "Are you sure you wish to remove this substitute part link?" +msgstr "" + +#: templates/js/translated/bom.js:582 +msgid "Remove Substitute Part" +msgstr "" + +#: templates/js/translated/bom.js:621 +msgid "Add Substitute" +msgstr "" + +#: templates/js/translated/bom.js:622 +msgid "Edit BOM Item Substitutes" +msgstr "" + +#: templates/js/translated/bom.js:739 +msgid "Substitutes Available" +msgstr "" + +#: templates/js/translated/bom.js:743 templates/js/translated/build.js:1407 +msgid "Variant stock allowed" +msgstr "" + +#: templates/js/translated/bom.js:748 +msgid "Open subassembly" +msgstr "" + +#: templates/js/translated/bom.js:815 templates/js/translated/build.js:1433 +msgid "No Stock Available" +msgstr "" + +#: templates/js/translated/bom.js:818 templates/js/translated/build.js:1436 +msgid "Includes substitute stock" +msgstr "" + +#: templates/js/translated/bom.js:828 +msgid "Substitutes" +msgstr "" + +#: templates/js/translated/bom.js:843 +msgid "Purchase Price Range" +msgstr "" + +#: templates/js/translated/bom.js:850 +msgid "Purchase Price Average" +msgstr "" + +#: templates/js/translated/bom.js:899 templates/js/translated/bom.js:990 +msgid "View BOM" +msgstr "" + +#: templates/js/translated/bom.js:961 +msgid "Validate BOM Item" +msgstr "" + +#: templates/js/translated/bom.js:963 +msgid "This line has been validated" +msgstr "" + +#: templates/js/translated/bom.js:965 +msgid "Edit substitute parts" +msgstr "" + +#: templates/js/translated/bom.js:967 templates/js/translated/bom.js:1153 +msgid "Edit BOM Item" +msgstr "" + +#: templates/js/translated/bom.js:969 templates/js/translated/bom.js:1136 +msgid "Delete BOM Item" +msgstr "" + +#: templates/js/translated/bom.js:1076 templates/js/translated/build.js:1139 +msgid "No BOM items found" +msgstr "" + +#: templates/js/translated/bom.js:1131 +msgid "Are you sure you want to delete this BOM item?" +msgstr "" + +#: templates/js/translated/bom.js:1333 templates/js/translated/build.js:1391 +msgid "Required Part" +msgstr "" + +#: templates/js/translated/bom.js:1355 +msgid "Inherited from parent BOM" +msgstr "" + +#: templates/js/translated/build.js:86 +msgid "Edit Build Order" +msgstr "" + +#: templates/js/translated/build.js:120 +msgid "Create Build Order" +msgstr "" + +#: templates/js/translated/build.js:141 +msgid "Build order is ready to be completed" +msgstr "" + +#: templates/js/translated/build.js:146 +msgid "Build Order is incomplete" +msgstr "" + +#: templates/js/translated/build.js:174 +msgid "Complete Build Order" +msgstr "" + +#: templates/js/translated/build.js:215 templates/js/translated/stock.js:90 +#: templates/js/translated/stock.js:180 +msgid "Next available serial number" +msgstr "" + +#: templates/js/translated/build.js:217 templates/js/translated/stock.js:92 +#: templates/js/translated/stock.js:182 +msgid "Latest serial number" +msgstr "" + +#: templates/js/translated/build.js:226 +msgid "The Bill of Materials contains trackable parts" +msgstr "" + +#: templates/js/translated/build.js:227 +msgid "Build outputs must be generated individually" +msgstr "" + +#: templates/js/translated/build.js:235 +msgid "Trackable parts can have serial numbers specified" +msgstr "" + +#: templates/js/translated/build.js:236 +msgid "Enter serial numbers to generate multiple single build outputs" +msgstr "" + +#: templates/js/translated/build.js:243 +msgid "Create Build Output" +msgstr "" + +#: templates/js/translated/build.js:274 +msgid "Allocate stock items to this build output" +msgstr "" + +#: templates/js/translated/build.js:285 +msgid "Unallocate stock from build output" +msgstr "" + +#: templates/js/translated/build.js:294 +msgid "Complete build output" +msgstr "" + +#: templates/js/translated/build.js:302 +msgid "Delete build output" +msgstr "" + +#: templates/js/translated/build.js:325 +msgid "Are you sure you wish to unallocate stock items from this build?" +msgstr "" + +#: templates/js/translated/build.js:343 +msgid "Unallocate Stock Items" +msgstr "" + +#: templates/js/translated/build.js:361 templates/js/translated/build.js:509 +msgid "Select Build Outputs" +msgstr "" + +#: templates/js/translated/build.js:362 templates/js/translated/build.js:510 +msgid "At least one build output must be selected" +msgstr "" + +#: templates/js/translated/build.js:416 templates/js/translated/build.js:564 +msgid "Output" +msgstr "" + +#: templates/js/translated/build.js:432 +msgid "Complete Build Outputs" +msgstr "" + +#: templates/js/translated/build.js:577 +msgid "Delete Build Outputs" +msgstr "" + +#: templates/js/translated/build.js:666 +msgid "No build order allocations found" +msgstr "" + +#: templates/js/translated/build.js:704 +msgid "Location not specified" +msgstr "" + +#: templates/js/translated/build.js:886 +msgid "No active build outputs found" +msgstr "" + +#: templates/js/translated/build.js:1348 templates/js/translated/build.js:2155 +#: templates/js/translated/order.js:2179 +msgid "Edit stock allocation" +msgstr "" + +#: templates/js/translated/build.js:1350 templates/js/translated/build.js:2156 +#: templates/js/translated/order.js:2180 +msgid "Delete stock allocation" +msgstr "" + +#: templates/js/translated/build.js:1368 +msgid "Edit Allocation" +msgstr "" + +#: templates/js/translated/build.js:1378 +msgid "Remove Allocation" +msgstr "" + +#: templates/js/translated/build.js:1403 +msgid "Substitute parts available" +msgstr "" + +#: templates/js/translated/build.js:1420 +msgid "Quantity Per" +msgstr "" + +#: templates/js/translated/build.js:1445 templates/js/translated/build.js:1700 +#: templates/js/translated/build.js:2151 templates/js/translated/order.js:2446 +msgid "Allocated" +msgstr "" + +#: templates/js/translated/build.js:1459 +msgid "loading" +msgstr "" + +#: templates/js/translated/build.js:1503 templates/js/translated/order.js:2526 +msgid "Build stock" +msgstr "" + +#: templates/js/translated/build.js:1507 templates/stock_table.html:50 +msgid "Order stock" +msgstr "" + +#: templates/js/translated/build.js:1510 templates/js/translated/order.js:2519 +msgid "Allocate stock" +msgstr "" + +#: templates/js/translated/build.js:1549 templates/js/translated/label.js:172 +#: templates/js/translated/order.js:1755 templates/js/translated/report.js:225 +msgid "Select Parts" +msgstr "" + +#: templates/js/translated/build.js:1550 templates/js/translated/order.js:1756 +msgid "You must select at least one part to allocate" +msgstr "" + +#: templates/js/translated/build.js:1599 templates/js/translated/order.js:1704 +msgid "Specify stock allocation quantity" +msgstr "" + +#: templates/js/translated/build.js:1673 +msgid "All Parts Allocated" +msgstr "" + +#: templates/js/translated/build.js:1674 +msgid "All selected parts have been fully allocated" +msgstr "" + +#: templates/js/translated/build.js:1688 templates/js/translated/order.js:1770 +msgid "Select source location (leave blank to take from all locations)" +msgstr "" + +#: templates/js/translated/build.js:1717 templates/js/translated/order.js:1805 +msgid "Confirm stock allocation" +msgstr "" + +#: templates/js/translated/build.js:1718 +msgid "Allocate Stock Items to Build Order" +msgstr "" + +#: templates/js/translated/build.js:1729 templates/js/translated/order.js:1818 +msgid "No matching stock locations" +msgstr "" + +#: templates/js/translated/build.js:1801 templates/js/translated/order.js:1895 +msgid "No matching stock items" +msgstr "" + +#: templates/js/translated/build.js:1898 +msgid "Automatic Stock Allocation" +msgstr "" + +#: templates/js/translated/build.js:1899 +msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines" +msgstr "" + +#: templates/js/translated/build.js:1901 +msgid "If a location is specifed, stock will only be allocated from that location" +msgstr "" + +#: templates/js/translated/build.js:1902 +msgid "If stock is considered interchangeable, it will be allocated from the first location it is found" +msgstr "" + +#: templates/js/translated/build.js:1903 +msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found" +msgstr "" + +#: templates/js/translated/build.js:1924 +msgid "Allocate Stock Items" +msgstr "" + +#: templates/js/translated/build.js:1962 +msgid "No builds matching query" +msgstr "" + +#: templates/js/translated/build.js:1979 templates/js/translated/part.js:1296 +#: templates/js/translated/part.js:1723 templates/js/translated/stock.js:1628 +#: templates/js/translated/stock.js:2281 +msgid "Select" +msgstr "" + +#: templates/js/translated/build.js:1999 +msgid "Build order is overdue" +msgstr "" + +#: templates/js/translated/build.js:2063 templates/js/translated/stock.js:2523 +msgid "No user information" +msgstr "" + +#: templates/js/translated/build.js:2075 +msgid "No information" +msgstr "" + +#: templates/js/translated/build.js:2132 +msgid "No parts allocated for" +msgstr "" + +#: templates/js/translated/company.js:65 +msgid "Add Manufacturer" +msgstr "" + +#: templates/js/translated/company.js:78 templates/js/translated/company.js:177 +msgid "Add Manufacturer Part" +msgstr "" + +#: templates/js/translated/company.js:99 +msgid "Edit Manufacturer Part" +msgstr "" + +#: templates/js/translated/company.js:108 +msgid "Delete Manufacturer Part" +msgstr "" + +#: templates/js/translated/company.js:165 templates/js/translated/order.js:248 +msgid "Add Supplier" +msgstr "" + +#: templates/js/translated/company.js:193 +msgid "Add Supplier Part" +msgstr "" + +#: templates/js/translated/company.js:208 +msgid "Edit Supplier Part" +msgstr "" + +#: templates/js/translated/company.js:218 +msgid "Delete Supplier Part" +msgstr "" + +#: templates/js/translated/company.js:286 +msgid "Add new Company" +msgstr "" + +#: templates/js/translated/company.js:363 +msgid "Parts Supplied" +msgstr "" + +#: templates/js/translated/company.js:372 +msgid "Parts Manufactured" +msgstr "" + +#: templates/js/translated/company.js:387 +msgid "No company information found" +msgstr "" + +#: templates/js/translated/company.js:406 +msgid "The following manufacturer parts will be deleted" +msgstr "" + +#: templates/js/translated/company.js:423 +msgid "Delete Manufacturer Parts" +msgstr "" + +#: templates/js/translated/company.js:480 +msgid "No manufacturer parts found" +msgstr "" + +#: templates/js/translated/company.js:500 +#: templates/js/translated/company.js:757 templates/js/translated/part.js:560 +#: templates/js/translated/part.js:645 +msgid "Template part" +msgstr "" + +#: templates/js/translated/company.js:504 +#: templates/js/translated/company.js:761 templates/js/translated/part.js:564 +#: templates/js/translated/part.js:649 +msgid "Assembled part" +msgstr "" + +#: templates/js/translated/company.js:631 templates/js/translated/part.js:739 +msgid "No parameters found" +msgstr "" + +#: templates/js/translated/company.js:668 templates/js/translated/part.js:781 +msgid "Edit parameter" +msgstr "" + +#: templates/js/translated/company.js:669 templates/js/translated/part.js:782 +msgid "Delete parameter" +msgstr "" + +#: templates/js/translated/company.js:688 templates/js/translated/part.js:799 +msgid "Edit Parameter" +msgstr "" + +#: templates/js/translated/company.js:699 templates/js/translated/part.js:811 +msgid "Delete Parameter" +msgstr "" + +#: templates/js/translated/company.js:737 +msgid "No supplier parts found" +msgstr "" + +#: templates/js/translated/filters.js:178 +#: templates/js/translated/filters.js:441 +msgid "true" +msgstr "" + +#: templates/js/translated/filters.js:182 +#: templates/js/translated/filters.js:442 +msgid "false" +msgstr "" + +#: templates/js/translated/filters.js:204 +msgid "Select filter" +msgstr "" + +#: templates/js/translated/filters.js:288 +msgid "Download data" +msgstr "" + +#: templates/js/translated/filters.js:291 +msgid "Reload data" +msgstr "" + +#: templates/js/translated/filters.js:295 +msgid "Add new filter" +msgstr "" + +#: templates/js/translated/filters.js:298 +msgid "Clear all filters" +msgstr "" + +#: templates/js/translated/filters.js:350 +msgid "Create filter" +msgstr "" + +#: templates/js/translated/forms.js:351 templates/js/translated/forms.js:366 +#: templates/js/translated/forms.js:380 templates/js/translated/forms.js:394 +msgid "Action Prohibited" +msgstr "" + +#: templates/js/translated/forms.js:353 +msgid "Create operation not allowed" +msgstr "" + +#: templates/js/translated/forms.js:368 +msgid "Update operation not allowed" +msgstr "" + +#: templates/js/translated/forms.js:382 +msgid "Delete operation not allowed" +msgstr "" + +#: templates/js/translated/forms.js:396 +msgid "View operation not allowed" +msgstr "" + +#: templates/js/translated/forms.js:627 +msgid "Keep this form open" +msgstr "" + +#: templates/js/translated/forms.js:702 +msgid "Enter a valid number" +msgstr "" + +#: templates/js/translated/forms.js:1194 templates/modals.html:19 +#: templates/modals.html:43 +msgid "Form errors exist" +msgstr "" + +#: templates/js/translated/forms.js:1623 +msgid "No results found" +msgstr "" + +#: templates/js/translated/forms.js:1833 templates/search.html:29 +msgid "Searching" +msgstr "" + +#: templates/js/translated/forms.js:2082 +msgid "Clear input" +msgstr "" + +#: templates/js/translated/forms.js:2547 +msgid "File Column" +msgstr "" + +#: templates/js/translated/forms.js:2547 +msgid "Field Name" +msgstr "" + +#: templates/js/translated/forms.js:2559 +msgid "Select Columns" +msgstr "" + +#: templates/js/translated/helpers.js:20 +msgid "YES" +msgstr "" + +#: templates/js/translated/helpers.js:22 +msgid "NO" +msgstr "" + +#: templates/js/translated/helpers.js:305 +msgid "Notes updated" +msgstr "" + +#: templates/js/translated/label.js:39 +msgid "Labels sent to printer" +msgstr "" + +#: templates/js/translated/label.js:60 templates/js/translated/report.js:118 +#: templates/js/translated/stock.js:1022 +msgid "Select Stock Items" +msgstr "" + +#: templates/js/translated/label.js:61 +msgid "Stock item(s) must be selected before printing labels" +msgstr "" + +#: templates/js/translated/label.js:79 templates/js/translated/label.js:133 +#: templates/js/translated/label.js:191 +msgid "No Labels Found" +msgstr "" + +#: templates/js/translated/label.js:80 +msgid "No labels found which match selected stock item(s)" +msgstr "" + +#: templates/js/translated/label.js:115 +msgid "Select Stock Locations" +msgstr "" + +#: templates/js/translated/label.js:116 +msgid "Stock location(s) must be selected before printing labels" +msgstr "" + +#: templates/js/translated/label.js:134 +msgid "No labels found which match selected stock location(s)" +msgstr "" + +#: templates/js/translated/label.js:173 +msgid "Part(s) must be selected before printing labels" +msgstr "" + +#: templates/js/translated/label.js:192 +msgid "No labels found which match the selected part(s)" +msgstr "" + +#: templates/js/translated/label.js:261 +msgid "Select Printer" +msgstr "" + +#: templates/js/translated/label.js:265 +msgid "Export to PDF" +msgstr "" + +#: templates/js/translated/label.js:304 +msgid "stock items selected" +msgstr "" + +#: templates/js/translated/label.js:312 templates/js/translated/label.js:328 +msgid "Select Label Template" +msgstr "" + +#: templates/js/translated/modals.js:76 templates/js/translated/modals.js:120 +#: templates/js/translated/modals.js:610 +msgid "Cancel" +msgstr "" + +#: templates/js/translated/modals.js:77 templates/js/translated/modals.js:119 +#: templates/js/translated/modals.js:677 templates/js/translated/modals.js:985 +#: templates/modals.html:28 templates/modals.html:51 +msgid "Submit" +msgstr "" + +#: templates/js/translated/modals.js:118 +msgid "Form Title" +msgstr "" + +#: templates/js/translated/modals.js:392 +msgid "Waiting for server..." +msgstr "" + +#: templates/js/translated/modals.js:551 +msgid "Show Error Information" +msgstr "" + +#: templates/js/translated/modals.js:609 +msgid "Accept" +msgstr "" + +#: templates/js/translated/modals.js:666 +msgid "Loading Data" +msgstr "" + +#: templates/js/translated/modals.js:937 +msgid "Invalid response from server" +msgstr "" + +#: templates/js/translated/modals.js:937 +msgid "Form data missing from server response" +msgstr "" + +#: templates/js/translated/modals.js:949 +msgid "Error posting form data" +msgstr "" + +#: templates/js/translated/modals.js:1046 +msgid "JSON response missing form data" +msgstr "" + +#: templates/js/translated/modals.js:1061 +msgid "Error 400: Bad Request" +msgstr "" + +#: templates/js/translated/modals.js:1062 +msgid "Server returned error code 400" +msgstr "" + +#: templates/js/translated/modals.js:1085 +msgid "Error requesting form data" +msgstr "" + +#: templates/js/translated/model_renderers.js:60 +msgid "Company ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:123 +msgid "Stock ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:149 +msgid "Location ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:166 +msgid "Build ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:265 +#: templates/js/translated/model_renderers.js:291 +msgid "Order ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:306 +msgid "Shipment ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:326 +msgid "Category ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:369 +msgid "Manufacturer Part ID" +msgstr "" + +#: templates/js/translated/model_renderers.js:398 +msgid "Supplier Part ID" +msgstr "" + +#: templates/js/translated/notification.js:231 +msgid "Mark as unread" +msgstr "" + +#: templates/js/translated/notification.js:235 +msgid "Mark as read" +msgstr "" + +#: templates/js/translated/notification.js:259 +msgid "No unread notifications" +msgstr "" + +#: templates/js/translated/notification.js:300 templates/notifications.html:10 +msgid "Notifications will load here" +msgstr "" + +#: templates/js/translated/order.js:75 +msgid "No stock items have been allocated to this shipment" +msgstr "" + +#: templates/js/translated/order.js:80 +msgid "The following stock items will be shipped" +msgstr "" + +#: templates/js/translated/order.js:120 +msgid "Complete Shipment" +msgstr "" + +#: templates/js/translated/order.js:126 +msgid "Confirm Shipment" +msgstr "" + +#: templates/js/translated/order.js:181 +msgid "Create New Shipment" +msgstr "" + +#: templates/js/translated/order.js:206 +msgid "Add Customer" +msgstr "" + +#: templates/js/translated/order.js:231 +msgid "Create Sales Order" +msgstr "" + +#: templates/js/translated/order.js:426 +msgid "Export Order" +msgstr "" + +#: templates/js/translated/order.js:520 +msgid "Select Line Items" +msgstr "" + +#: templates/js/translated/order.js:521 +msgid "At least one line item must be selected" +msgstr "" + +#: templates/js/translated/order.js:541 templates/js/translated/order.js:640 +msgid "Add batch code" +msgstr "" + +#: templates/js/translated/order.js:547 templates/js/translated/order.js:651 +msgid "Add serial numbers" +msgstr "" + +#: templates/js/translated/order.js:559 +msgid "Quantity to receive" +msgstr "" + +#: templates/js/translated/order.js:623 templates/js/translated/stock.js:2084 +msgid "Stock Status" +msgstr "" + +#: templates/js/translated/order.js:712 +msgid "Order Code" +msgstr "" + +#: templates/js/translated/order.js:713 +msgid "Ordered" +msgstr "" + +#: templates/js/translated/order.js:715 +msgid "Quantity to Receive" +msgstr "" + +#: templates/js/translated/order.js:734 +msgid "Confirm receipt of items" +msgstr "" + +#: templates/js/translated/order.js:735 +msgid "Receive Purchase Order Items" +msgstr "" + +#: templates/js/translated/order.js:925 templates/js/translated/part.js:852 +msgid "No purchase orders found" +msgstr "" + +#: templates/js/translated/order.js:950 templates/js/translated/order.js:1426 +msgid "Order is overdue" +msgstr "" + +#: templates/js/translated/order.js:1074 templates/js/translated/order.js:2577 +msgid "Duplicate Line Item" +msgstr "" + +#: templates/js/translated/order.js:1104 templates/js/translated/order.js:2599 +msgid "Edit Line Item" +msgstr "" + +#: templates/js/translated/order.js:1117 templates/js/translated/order.js:2610 +msgid "Delete Line Item" +msgstr "" + +#: templates/js/translated/order.js:1160 +msgid "No line items found" +msgstr "" + +#: templates/js/translated/order.js:1187 templates/js/translated/order.js:2335 +msgid "Total" +msgstr "" + +#: templates/js/translated/order.js:1241 templates/js/translated/order.js:2360 +#: templates/js/translated/part.js:1940 templates/js/translated/part.js:2284 +msgid "Unit Price" +msgstr "" + +#: templates/js/translated/order.js:1256 templates/js/translated/order.js:2376 +msgid "Total Price" +msgstr "" + +#: templates/js/translated/order.js:1297 templates/js/translated/order.js:2418 +#: templates/js/translated/part.js:961 +msgid "This line item is overdue" +msgstr "" + +#: templates/js/translated/order.js:1356 templates/js/translated/part.js:1007 +msgid "Receive line item" +msgstr "" + +#: templates/js/translated/order.js:1360 templates/js/translated/order.js:2532 +msgid "Duplicate line item" +msgstr "" + +#: templates/js/translated/order.js:1361 templates/js/translated/order.js:2533 +msgid "Edit line item" +msgstr "" + +#: templates/js/translated/order.js:1362 templates/js/translated/order.js:2537 +msgid "Delete line item" +msgstr "" + +#: templates/js/translated/order.js:1402 +msgid "No sales orders found" +msgstr "" + +#: templates/js/translated/order.js:1440 +msgid "Invalid Customer" +msgstr "" + +#: templates/js/translated/order.js:1527 +msgid "Edit shipment" +msgstr "" + +#: templates/js/translated/order.js:1530 +msgid "Complete shipment" +msgstr "" + +#: templates/js/translated/order.js:1535 +msgid "Delete shipment" +msgstr "" + +#: templates/js/translated/order.js:1555 +msgid "Edit Shipment" +msgstr "" + +#: templates/js/translated/order.js:1572 +msgid "Delete Shipment" +msgstr "" + +#: templates/js/translated/order.js:1606 +msgid "No matching shipments found" +msgstr "" + +#: templates/js/translated/order.js:1616 +msgid "Shipment Reference" +msgstr "" + +#: templates/js/translated/order.js:1640 +msgid "Not shipped" +msgstr "" + +#: templates/js/translated/order.js:1646 +msgid "Tracking" +msgstr "" + +#: templates/js/translated/order.js:1806 +msgid "Allocate Stock Items to Sales Order" +msgstr "" + +#: templates/js/translated/order.js:2014 +msgid "No sales order allocations found" +msgstr "" + +#: templates/js/translated/order.js:2095 +msgid "Edit Stock Allocation" +msgstr "" + +#: templates/js/translated/order.js:2112 +msgid "Confirm Delete Operation" +msgstr "" + +#: templates/js/translated/order.js:2113 +msgid "Delete Stock Allocation" +msgstr "" + +#: templates/js/translated/order.js:2156 templates/js/translated/order.js:2245 +#: templates/js/translated/stock.js:1544 +msgid "Shipped to customer" +msgstr "" + +#: templates/js/translated/order.js:2164 templates/js/translated/order.js:2254 +msgid "Stock location not specified" +msgstr "" + +#: templates/js/translated/order.js:2516 +msgid "Allocate serial numbers" +msgstr "" + +#: templates/js/translated/order.js:2522 +msgid "Purchase stock" +msgstr "" + +#: templates/js/translated/order.js:2529 templates/js/translated/order.js:2719 +msgid "Calculate price" +msgstr "" + +#: templates/js/translated/order.js:2541 +msgid "Cannot be deleted as items have been shipped" +msgstr "" + +#: templates/js/translated/order.js:2544 +msgid "Cannot be deleted as items have been allocated" +msgstr "" + +#: templates/js/translated/order.js:2625 +msgid "Allocate Serial Numbers" +msgstr "" + +#: templates/js/translated/order.js:2727 +msgid "Update Unit Price" +msgstr "" + +#: templates/js/translated/order.js:2741 +msgid "No matching line items" +msgstr "" + +#: templates/js/translated/part.js:55 +msgid "Part Attributes" +msgstr "" + +#: templates/js/translated/part.js:59 +msgid "Part Creation Options" +msgstr "" + +#: templates/js/translated/part.js:63 +msgid "Part Duplication Options" +msgstr "" + +#: templates/js/translated/part.js:67 +msgid "Supplier Options" +msgstr "" + +#: templates/js/translated/part.js:81 +msgid "Add Part Category" +msgstr "" + +#: templates/js/translated/part.js:165 +msgid "Create Initial Stock" +msgstr "" + +#: templates/js/translated/part.js:166 +msgid "Create an initial stock item for this part" +msgstr "" + +#: templates/js/translated/part.js:173 +msgid "Initial Stock Quantity" +msgstr "" + +#: templates/js/translated/part.js:174 +msgid "Specify initial stock quantity for this part" +msgstr "" + +#: templates/js/translated/part.js:181 +msgid "Select destination stock location" +msgstr "" + +#: templates/js/translated/part.js:199 +msgid "Copy Category Parameters" +msgstr "" + +#: templates/js/translated/part.js:200 +msgid "Copy parameter templates from selected part category" +msgstr "" + +#: templates/js/translated/part.js:208 +msgid "Add Supplier Data" +msgstr "" + +#: templates/js/translated/part.js:209 +msgid "Create initial supplier data for this part" +msgstr "" + +#: templates/js/translated/part.js:265 +msgid "Copy Image" +msgstr "" + +#: templates/js/translated/part.js:266 +msgid "Copy image from original part" +msgstr "" + +#: templates/js/translated/part.js:274 +msgid "Copy bill of materials from original part" +msgstr "" + +#: templates/js/translated/part.js:281 +msgid "Copy Parameters" +msgstr "" + +#: templates/js/translated/part.js:282 +msgid "Copy parameter data from original part" +msgstr "" + +#: templates/js/translated/part.js:295 +msgid "Parent part category" +msgstr "" + +#: templates/js/translated/part.js:340 +msgid "Edit Part" +msgstr "" + +#: templates/js/translated/part.js:342 +msgid "Part edited" +msgstr "" + +#: templates/js/translated/part.js:353 +msgid "Create Part Variant" +msgstr "" + +#: templates/js/translated/part.js:423 +msgid "You are subscribed to notifications for this item" +msgstr "" + +#: templates/js/translated/part.js:425 +msgid "You have subscribed to notifications for this item" +msgstr "" + +#: templates/js/translated/part.js:430 +msgid "Subscribe to notifications for this item" +msgstr "" + +#: templates/js/translated/part.js:432 +msgid "You have unsubscribed to notifications for this item" +msgstr "" + +#: templates/js/translated/part.js:449 +msgid "Validating the BOM will mark each line item as valid" +msgstr "" + +#: templates/js/translated/part.js:459 +msgid "Validate Bill of Materials" +msgstr "" + +#: templates/js/translated/part.js:462 +msgid "Validated Bill of Materials" +msgstr "" + +#: templates/js/translated/part.js:487 +msgid "Copy Bill of Materials" +msgstr "" + +#: templates/js/translated/part.js:508 templates/js/translated/part.js:1379 +#: templates/js/translated/table_filters.js:452 +msgid "Low stock" +msgstr "" + +#: templates/js/translated/part.js:518 templates/js/translated/part.js:1391 +msgid "No stock available" +msgstr "" + +#: templates/js/translated/part.js:552 templates/js/translated/part.js:637 +msgid "Trackable part" +msgstr "" + +#: templates/js/translated/part.js:556 templates/js/translated/part.js:641 +msgid "Virtual part" +msgstr "" + +#: templates/js/translated/part.js:568 +msgid "Subscribed part" +msgstr "" + +#: templates/js/translated/part.js:572 +msgid "Salable part" +msgstr "" + +#: templates/js/translated/part.js:687 +msgid "No variants found" +msgstr "" + +#: templates/js/translated/part.js:1077 +msgid "Delete part relationship" +msgstr "" + +#: templates/js/translated/part.js:1101 +msgid "Delete Part Relationship" +msgstr "" + +#: templates/js/translated/part.js:1166 templates/js/translated/part.js:1462 +msgid "No parts found" +msgstr "" + +#: templates/js/translated/part.js:1205 +msgid "Not available" +msgstr "" + +#: templates/js/translated/part.js:1356 +msgid "No category" +msgstr "" + +#: templates/js/translated/part.js:1486 templates/js/translated/part.js:1658 +#: templates/js/translated/stock.js:2242 +msgid "Display as list" +msgstr "" + +#: templates/js/translated/part.js:1502 +msgid "Display as grid" +msgstr "" + +#: templates/js/translated/part.js:1677 templates/js/translated/stock.js:2261 +msgid "Display as tree" +msgstr "" + +#: templates/js/translated/part.js:1741 +msgid "Subscribed category" +msgstr "" + +#: templates/js/translated/part.js:1755 templates/js/translated/stock.js:2305 +msgid "Path" +msgstr "" + +#: templates/js/translated/part.js:1799 +msgid "No test templates matching query" +msgstr "" + +#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1242 +msgid "Edit test result" +msgstr "" + +#: templates/js/translated/part.js:1851 templates/js/translated/stock.js:1243 +#: templates/js/translated/stock.js:1502 +msgid "Delete test result" +msgstr "" + +#: templates/js/translated/part.js:1857 +msgid "This test is defined for a parent part" +msgstr "" + +#: templates/js/translated/part.js:1879 +msgid "Edit Test Result Template" +msgstr "" + +#: templates/js/translated/part.js:1893 +msgid "Delete Test Result Template" +msgstr "" + +#: templates/js/translated/part.js:1918 +#, python-brace-format +msgid "No ${human_name} information found" +msgstr "" + +#: templates/js/translated/part.js:1973 +#, python-brace-format +msgid "Edit ${human_name}" +msgstr "" + +#: templates/js/translated/part.js:1974 +#, python-brace-format +msgid "Delete ${human_name}" +msgstr "" + +#: templates/js/translated/part.js:2079 +msgid "Current Stock" +msgstr "" + +#: templates/js/translated/part.js:2112 +msgid "No scheduling information available for this part" +msgstr "" + +#: templates/js/translated/part.js:2138 +msgid "Scheduled Stock Quantities" +msgstr "" + +#: templates/js/translated/part.js:2208 +msgid "Single Price" +msgstr "" + +#: templates/js/translated/part.js:2227 +msgid "Single Price Difference" +msgstr "" + +#: templates/js/translated/plugin.js:22 +msgid "The Plugin was installed" +msgstr "" + +#: templates/js/translated/report.js:67 +msgid "items selected" +msgstr "" + +#: templates/js/translated/report.js:75 +msgid "Select Report Template" +msgstr "" + +#: templates/js/translated/report.js:90 +msgid "Select Test Report Template" +msgstr "" + +#: templates/js/translated/report.js:119 +msgid "Stock item(s) must be selected before printing reports" +msgstr "" + +#: templates/js/translated/report.js:136 templates/js/translated/report.js:189 +#: templates/js/translated/report.js:243 templates/js/translated/report.js:297 +#: templates/js/translated/report.js:351 +msgid "No Reports Found" +msgstr "" + +#: templates/js/translated/report.js:137 +msgid "No report templates found which match selected stock item(s)" +msgstr "" + +#: templates/js/translated/report.js:172 +msgid "Select Builds" +msgstr "" + +#: templates/js/translated/report.js:173 +msgid "Build(s) must be selected before printing reports" +msgstr "" + +#: templates/js/translated/report.js:190 +msgid "No report templates found which match selected build(s)" +msgstr "" + +#: templates/js/translated/report.js:226 +msgid "Part(s) must be selected before printing reports" +msgstr "" + +#: templates/js/translated/report.js:244 +msgid "No report templates found which match selected part(s)" +msgstr "" + +#: templates/js/translated/report.js:279 +msgid "Select Purchase Orders" +msgstr "" + +#: templates/js/translated/report.js:280 +msgid "Purchase Order(s) must be selected before printing report" +msgstr "" + +#: templates/js/translated/report.js:298 templates/js/translated/report.js:352 +msgid "No report templates found which match selected orders" +msgstr "" + +#: templates/js/translated/report.js:333 +msgid "Select Sales Orders" +msgstr "" + +#: templates/js/translated/report.js:334 +msgid "Sales Order(s) must be selected before printing report" +msgstr "" + +#: templates/js/translated/search.js:286 +msgid "Minimize results" +msgstr "" + +#: templates/js/translated/search.js:289 +msgid "Remove results" +msgstr "" + +#: templates/js/translated/stock.js:72 +msgid "Serialize Stock Item" +msgstr "" + +#: templates/js/translated/stock.js:100 +msgid "Confirm Stock Serialization" +msgstr "" + +#: templates/js/translated/stock.js:109 +msgid "Parent stock location" +msgstr "" + +#: templates/js/translated/stock.js:153 +msgid "New Stock Location" +msgstr "" + +#: templates/js/translated/stock.js:193 +msgid "This part cannot be serialized" +msgstr "" + +#: templates/js/translated/stock.js:232 +msgid "Enter initial quantity for this stock item" +msgstr "" + +#: templates/js/translated/stock.js:238 +msgid "Enter serial numbers for new stock (or leave blank)" +msgstr "" + +#: templates/js/translated/stock.js:303 +msgid "Stock item duplicated" +msgstr "" + +#: templates/js/translated/stock.js:393 +msgid "Created new stock item" +msgstr "" + +#: templates/js/translated/stock.js:406 +msgid "Created multiple stock items" +msgstr "" + +#: templates/js/translated/stock.js:431 +msgid "Find Serial Number" +msgstr "" + +#: templates/js/translated/stock.js:435 templates/js/translated/stock.js:436 +msgid "Enter serial number" +msgstr "" + +#: templates/js/translated/stock.js:452 +msgid "Enter a serial number" +msgstr "" + +#: templates/js/translated/stock.js:472 +msgid "No matching serial number" +msgstr "" + +#: templates/js/translated/stock.js:481 +msgid "More than one matching result found" +msgstr "" + +#: templates/js/translated/stock.js:604 +msgid "Confirm stock assignment" +msgstr "" + +#: templates/js/translated/stock.js:605 +msgid "Assign Stock to Customer" +msgstr "" + +#: templates/js/translated/stock.js:682 +msgid "Warning: Merge operation cannot be reversed" +msgstr "" + +#: templates/js/translated/stock.js:683 +msgid "Some information will be lost when merging stock items" +msgstr "" + +#: templates/js/translated/stock.js:685 +msgid "Stock transaction history will be deleted for merged items" +msgstr "" + +#: templates/js/translated/stock.js:686 +msgid "Supplier part information will be deleted for merged items" +msgstr "" + +#: templates/js/translated/stock.js:772 +msgid "Confirm stock item merge" +msgstr "" + +#: templates/js/translated/stock.js:773 +msgid "Merge Stock Items" +msgstr "" + +#: templates/js/translated/stock.js:868 +msgid "Transfer Stock" +msgstr "" + +#: templates/js/translated/stock.js:869 +msgid "Move" +msgstr "" + +#: templates/js/translated/stock.js:875 +msgid "Count Stock" +msgstr "" + +#: templates/js/translated/stock.js:876 +msgid "Count" +msgstr "" + +#: templates/js/translated/stock.js:880 +msgid "Remove Stock" +msgstr "" + +#: templates/js/translated/stock.js:881 +msgid "Take" +msgstr "" + +#: templates/js/translated/stock.js:885 +msgid "Add Stock" +msgstr "" + +#: templates/js/translated/stock.js:886 users/models.py:214 +msgid "Add" +msgstr "" + +#: templates/js/translated/stock.js:890 +msgid "Delete Stock" +msgstr "" + +#: templates/js/translated/stock.js:983 +msgid "Quantity cannot be adjusted for serialized stock" +msgstr "" + +#: templates/js/translated/stock.js:983 +msgid "Specify stock quantity" +msgstr "" + +#: templates/js/translated/stock.js:1023 +msgid "You must select at least one available stock item" +msgstr "" + +#: templates/js/translated/stock.js:1181 +msgid "PASS" +msgstr "" + +#: templates/js/translated/stock.js:1183 +msgid "FAIL" +msgstr "" + +#: templates/js/translated/stock.js:1188 +msgid "NO RESULT" +msgstr "" + +#: templates/js/translated/stock.js:1235 +msgid "Pass test" +msgstr "" + +#: templates/js/translated/stock.js:1238 +msgid "Add test result" +msgstr "" + +#: templates/js/translated/stock.js:1264 +msgid "No test results found" +msgstr "" + +#: templates/js/translated/stock.js:1320 +msgid "Test Date" +msgstr "" + +#: templates/js/translated/stock.js:1485 +msgid "Edit Test Result" +msgstr "" + +#: templates/js/translated/stock.js:1507 +msgid "Delete Test Result" +msgstr "" + +#: templates/js/translated/stock.js:1536 +msgid "In production" +msgstr "" + +#: templates/js/translated/stock.js:1540 +msgid "Installed in Stock Item" +msgstr "" + +#: templates/js/translated/stock.js:1548 +msgid "Assigned to Sales Order" +msgstr "" + +#: templates/js/translated/stock.js:1554 +msgid "No stock location set" +msgstr "" + +#: templates/js/translated/stock.js:1712 +msgid "Stock item is in production" +msgstr "" + +#: templates/js/translated/stock.js:1717 +msgid "Stock item assigned to sales order" +msgstr "" + +#: templates/js/translated/stock.js:1720 +msgid "Stock item assigned to customer" +msgstr "" + +#: templates/js/translated/stock.js:1724 +msgid "Stock item has expired" +msgstr "" + +#: templates/js/translated/stock.js:1726 +msgid "Stock item will expire soon" +msgstr "" + +#: templates/js/translated/stock.js:1732 +msgid "Serialized stock item has been allocated" +msgstr "" + +#: templates/js/translated/stock.js:1734 +msgid "Stock item has been fully allocated" +msgstr "" + +#: templates/js/translated/stock.js:1736 +msgid "Stock item has been partially allocated" +msgstr "" + +#: templates/js/translated/stock.js:1741 +msgid "Stock item has been installed in another item" +msgstr "" + +#: templates/js/translated/stock.js:1748 +msgid "Stock item has been rejected" +msgstr "" + +#: templates/js/translated/stock.js:1750 +msgid "Stock item is lost" +msgstr "" + +#: templates/js/translated/stock.js:1752 +msgid "Stock item is destroyed" +msgstr "" + +#: templates/js/translated/stock.js:1756 +#: templates/js/translated/table_filters.js:188 +msgid "Depleted" +msgstr "" + +#: templates/js/translated/stock.js:1807 +msgid "Stocktake" +msgstr "" + +#: templates/js/translated/stock.js:1889 +msgid "Supplier part not specified" +msgstr "" + +#: templates/js/translated/stock.js:1927 +msgid "No stock items matching query" +msgstr "" + +#: templates/js/translated/stock.js:2099 +msgid "Set Stock Status" +msgstr "" + +#: templates/js/translated/stock.js:2113 +msgid "Select Status Code" +msgstr "" + +#: templates/js/translated/stock.js:2114 +msgid "Status code must be selected" +msgstr "" + +#: templates/js/translated/stock.js:2369 +msgid "Details" +msgstr "" + +#: templates/js/translated/stock.js:2385 +msgid "Part information unavailable" +msgstr "" + +#: templates/js/translated/stock.js:2407 +msgid "Location no longer exists" +msgstr "" + +#: templates/js/translated/stock.js:2426 +msgid "Purchase order no longer exists" +msgstr "" + +#: templates/js/translated/stock.js:2445 +msgid "Customer no longer exists" +msgstr "" + +#: templates/js/translated/stock.js:2463 +msgid "Stock item no longer exists" +msgstr "" + +#: templates/js/translated/stock.js:2486 +msgid "Added" +msgstr "" + +#: templates/js/translated/stock.js:2494 +msgid "Removed" +msgstr "" + +#: templates/js/translated/stock.js:2570 +msgid "No installed items" +msgstr "" + +#: templates/js/translated/stock.js:2621 +msgid "Uninstall Stock Item" +msgstr "" + +#: templates/js/translated/stock.js:2657 +msgid "Install another stock item into this item" +msgstr "" + +#: templates/js/translated/stock.js:2658 +msgid "Stock items can only be installed if they meet the following criteria" +msgstr "" + +#: templates/js/translated/stock.js:2660 +msgid "The Stock Item links to a Part which is the BOM for this Stock Item" +msgstr "" + +#: templates/js/translated/stock.js:2661 +msgid "The Stock Item is currently available in stock" +msgstr "" + +#: templates/js/translated/stock.js:2662 +msgid "The Stock Item is not already installed in another item" +msgstr "" + +#: templates/js/translated/stock.js:2663 +msgid "The Stock Item is tracked by either a batch code or serial number" +msgstr "" + +#: templates/js/translated/stock.js:2676 +msgid "Select part to install" +msgstr "" + +#: templates/js/translated/table_filters.js:56 +msgid "Trackable Part" +msgstr "" + +#: templates/js/translated/table_filters.js:60 +msgid "Assembled Part" +msgstr "" + +#: templates/js/translated/table_filters.js:64 +msgid "Validated" +msgstr "" + +#: templates/js/translated/table_filters.js:72 +msgid "Allow Variant Stock" +msgstr "" + +#: templates/js/translated/table_filters.js:110 +#: templates/js/translated/table_filters.js:183 +msgid "Include sublocations" +msgstr "" + +#: templates/js/translated/table_filters.js:111 +msgid "Include locations" +msgstr "" + +#: templates/js/translated/table_filters.js:121 +#: templates/js/translated/table_filters.js:122 +#: templates/js/translated/table_filters.js:429 +msgid "Include subcategories" +msgstr "" + +#: templates/js/translated/table_filters.js:126 +#: templates/js/translated/table_filters.js:468 +msgid "Subscribed" +msgstr "" + +#: templates/js/translated/table_filters.js:136 +#: templates/js/translated/table_filters.js:218 +msgid "Is Serialized" +msgstr "" + +#: templates/js/translated/table_filters.js:139 +#: templates/js/translated/table_filters.js:225 +msgid "Serial number GTE" +msgstr "" + +#: templates/js/translated/table_filters.js:140 +#: templates/js/translated/table_filters.js:226 +msgid "Serial number greater than or equal to" +msgstr "" + +#: templates/js/translated/table_filters.js:143 +#: templates/js/translated/table_filters.js:229 +msgid "Serial number LTE" +msgstr "" + +#: templates/js/translated/table_filters.js:144 +#: templates/js/translated/table_filters.js:230 +msgid "Serial number less than or equal to" +msgstr "" + +#: templates/js/translated/table_filters.js:147 +#: templates/js/translated/table_filters.js:148 +#: templates/js/translated/table_filters.js:221 +#: templates/js/translated/table_filters.js:222 +msgid "Serial number" +msgstr "" + +#: templates/js/translated/table_filters.js:152 +#: templates/js/translated/table_filters.js:243 +msgid "Batch code" +msgstr "" + +#: templates/js/translated/table_filters.js:163 +#: templates/js/translated/table_filters.js:401 +msgid "Active parts" +msgstr "" + +#: templates/js/translated/table_filters.js:164 +msgid "Show stock for active parts" +msgstr "" + +#: templates/js/translated/table_filters.js:169 +msgid "Part is an assembly" +msgstr "" + +#: templates/js/translated/table_filters.js:173 +msgid "Is allocated" +msgstr "" + +#: templates/js/translated/table_filters.js:174 +msgid "Item has been allocated" +msgstr "" + +#: templates/js/translated/table_filters.js:179 +msgid "Stock is available for use" +msgstr "" + +#: templates/js/translated/table_filters.js:184 +msgid "Include stock in sublocations" +msgstr "" + +#: templates/js/translated/table_filters.js:189 +msgid "Show stock items which are depleted" +msgstr "" + +#: templates/js/translated/table_filters.js:194 +msgid "Show items which are in stock" +msgstr "" + +#: templates/js/translated/table_filters.js:198 +msgid "In Production" +msgstr "" + +#: templates/js/translated/table_filters.js:199 +msgid "Show items which are in production" +msgstr "" + +#: templates/js/translated/table_filters.js:203 +msgid "Include Variants" +msgstr "" + +#: templates/js/translated/table_filters.js:204 +msgid "Include stock items for variant parts" +msgstr "" + +#: templates/js/translated/table_filters.js:208 +msgid "Installed" +msgstr "" + +#: templates/js/translated/table_filters.js:209 +msgid "Show stock items which are installed in another item" +msgstr "" + +#: templates/js/translated/table_filters.js:214 +msgid "Show items which have been assigned to a customer" +msgstr "" + +#: templates/js/translated/table_filters.js:234 +#: templates/js/translated/table_filters.js:235 +msgid "Stock status" +msgstr "" + +#: templates/js/translated/table_filters.js:238 +msgid "Has batch code" +msgstr "" + +#: templates/js/translated/table_filters.js:246 +msgid "Tracked" +msgstr "" + +#: templates/js/translated/table_filters.js:247 +msgid "Stock item is tracked by either batch code or serial number" +msgstr "" + +#: templates/js/translated/table_filters.js:252 +msgid "Has purchase price" +msgstr "" + +#: templates/js/translated/table_filters.js:253 +msgid "Show stock items which have a purchase price set" +msgstr "" + +#: templates/js/translated/table_filters.js:262 +msgid "Show stock items which have expired" +msgstr "" + +#: templates/js/translated/table_filters.js:268 +msgid "Show stock which is close to expiring" +msgstr "" + +#: templates/js/translated/table_filters.js:280 +msgid "Test Passed" +msgstr "" + +#: templates/js/translated/table_filters.js:284 +msgid "Include Installed Items" +msgstr "" + +#: templates/js/translated/table_filters.js:303 +msgid "Build status" +msgstr "" + +#: templates/js/translated/table_filters.js:316 +#: templates/js/translated/table_filters.js:357 +msgid "Assigned to me" +msgstr "" + +#: templates/js/translated/table_filters.js:333 +#: templates/js/translated/table_filters.js:344 +#: templates/js/translated/table_filters.js:374 +msgid "Order status" +msgstr "" + +#: templates/js/translated/table_filters.js:349 +#: templates/js/translated/table_filters.js:366 +#: templates/js/translated/table_filters.js:379 +msgid "Outstanding" +msgstr "" + +#: templates/js/translated/table_filters.js:430 +msgid "Include parts in subcategories" +msgstr "" + +#: templates/js/translated/table_filters.js:434 +msgid "Has IPN" +msgstr "" + +#: templates/js/translated/table_filters.js:435 +msgid "Part has internal part number" +msgstr "" + +#: templates/js/translated/table_filters.js:440 +msgid "Show active parts" +msgstr "" + +#: templates/js/translated/table_filters.js:448 +msgid "In stock" +msgstr "" + +#: templates/js/translated/table_filters.js:456 +msgid "Available stock" +msgstr "" + +#: templates/js/translated/table_filters.js:480 +msgid "Purchasable" +msgstr "" + +#: templates/js/translated/tables.js:50 +msgid "Export Table Data" +msgstr "" + +#: templates/js/translated/tables.js:54 +msgid "Select File Format" +msgstr "" + +#: templates/js/translated/tables.js:433 +msgid "Loading data" +msgstr "" + +#: templates/js/translated/tables.js:436 +msgid "rows per page" +msgstr "" + +#: templates/js/translated/tables.js:441 +msgid "Showing all rows" +msgstr "" + +#: templates/js/translated/tables.js:443 +msgid "Showing" +msgstr "" + +#: templates/js/translated/tables.js:443 +msgid "to" +msgstr "" + +#: templates/js/translated/tables.js:443 +msgid "of" +msgstr "" + +#: templates/js/translated/tables.js:443 +msgid "rows" +msgstr "" + +#: templates/js/translated/tables.js:447 templates/navbar.html:94 +#: templates/search.html:8 templates/search_form.html:6 +#: templates/search_form.html:7 +msgid "Search" +msgstr "" + +#: templates/js/translated/tables.js:450 +msgid "No matching results" +msgstr "" + +#: templates/js/translated/tables.js:453 +msgid "Hide/Show pagination" +msgstr "" + +#: templates/js/translated/tables.js:456 +msgid "Refresh" +msgstr "" + +#: templates/js/translated/tables.js:459 +msgid "Toggle" +msgstr "" + +#: templates/js/translated/tables.js:462 +msgid "Columns" +msgstr "" + +#: templates/js/translated/tables.js:465 +msgid "All" +msgstr "" + +#: templates/navbar.html:42 +msgid "Buy" +msgstr "" + +#: templates/navbar.html:54 +msgid "Sell" +msgstr "" + +#: templates/navbar.html:108 +msgid "Show Notifications" +msgstr "" + +#: templates/navbar.html:111 +msgid "New Notifications" +msgstr "" + +#: templates/navbar.html:132 +msgid "Logout" +msgstr "" + +#: templates/navbar.html:134 +msgid "Login" +msgstr "" + +#: templates/navbar.html:154 +msgid "About InvenTree" +msgstr "" + +#: templates/navbar_demo.html:5 +msgid "InvenTree demo mode" +msgstr "" + +#: templates/notes_buttons.html:6 templates/notes_buttons.html:7 +msgid "Save" +msgstr "" + +#: templates/notifications.html:13 +msgid "Show all notifications and history" +msgstr "" + +#: templates/qr_code.html:11 +msgid "QR data not provided" +msgstr "" + +#: templates/registration/logged_out.html:6 +msgid "You were logged out successfully." +msgstr "" + +#: templates/registration/logged_out.html:8 +msgid "Log in again" +msgstr "" + +#: templates/search.html:9 +msgid "Show full search results" +msgstr "" + +#: templates/search.html:12 +msgid "Clear search" +msgstr "" + +#: templates/search.html:16 +msgid "Filter results" +msgstr "" + +#: templates/search.html:20 +msgid "Close search menu" +msgstr "" + +#: templates/search.html:35 +msgid "No search results" +msgstr "" + +#: templates/stats.html:9 +msgid "Server" +msgstr "" + +#: templates/stats.html:13 +msgid "Instance Name" +msgstr "" + +#: templates/stats.html:18 +msgid "Database" +msgstr "" + +#: templates/stats.html:26 +msgid "Server is running in debug mode" +msgstr "" + +#: templates/stats.html:33 +msgid "Docker Mode" +msgstr "" + +#: templates/stats.html:34 +msgid "Server is deployed using docker" +msgstr "" + +#: templates/stats.html:39 +msgid "Plugin Support" +msgstr "" + +#: templates/stats.html:43 +msgid "Plugin support enabled" +msgstr "" + +#: templates/stats.html:45 +msgid "Plugin support disabled" +msgstr "" + +#: templates/stats.html:52 +msgid "Server status" +msgstr "" + +#: templates/stats.html:55 +msgid "Healthy" +msgstr "" + +#: templates/stats.html:57 +msgid "Issues detected" +msgstr "" + +#: templates/stats.html:64 +msgid "Background Worker" +msgstr "" + +#: templates/stats.html:67 +msgid "Background worker not running" +msgstr "" + +#: templates/stats.html:75 +msgid "Email Settings" +msgstr "" + +#: templates/stats.html:78 +msgid "Email settings not configured" +msgstr "" + +#: templates/stock_table.html:17 +msgid "Barcode Actions" +msgstr "" + +#: templates/stock_table.html:33 +msgid "Print test reports" +msgstr "" + +#: templates/stock_table.html:40 +msgid "Stock Options" +msgstr "" + +#: templates/stock_table.html:45 +msgid "Add to selected stock items" +msgstr "" + +#: templates/stock_table.html:46 +msgid "Remove from selected stock items" +msgstr "" + +#: templates/stock_table.html:47 +msgid "Stocktake selected stock items" +msgstr "" + +#: templates/stock_table.html:48 +msgid "Move selected stock items" +msgstr "" + +#: templates/stock_table.html:49 +msgid "Merge selected stock items" +msgstr "" + +#: templates/stock_table.html:49 +msgid "Merge stock" +msgstr "" + +#: templates/stock_table.html:50 +msgid "Order selected items" +msgstr "" + +#: templates/stock_table.html:52 +msgid "Change status" +msgstr "" + +#: templates/stock_table.html:52 +msgid "Change stock status" +msgstr "" + +#: templates/stock_table.html:55 +msgid "Delete selected items" +msgstr "" + +#: templates/stock_table.html:55 +msgid "Delete stock" +msgstr "" + +#: templates/yesnolabel.html:4 +msgid "Yes" +msgstr "" + +#: templates/yesnolabel.html:6 +msgid "No" +msgstr "" + +#: users/admin.py:64 +msgid "Users" +msgstr "" + +#: users/admin.py:65 +msgid "Select which users are assigned to this group" +msgstr "" + +#: users/admin.py:187 +msgid "The following users are members of multiple groups:" +msgstr "" + +#: users/admin.py:210 +msgid "Personal info" +msgstr "" + +#: users/admin.py:211 +msgid "Permissions" +msgstr "" + +#: users/admin.py:214 +msgid "Important dates" +msgstr "" + +#: users/models.py:201 +msgid "Permission set" +msgstr "" + +#: users/models.py:209 +msgid "Group" +msgstr "" + +#: users/models.py:212 +msgid "View" +msgstr "" + +#: users/models.py:212 +msgid "Permission to view items" +msgstr "" + +#: users/models.py:214 +msgid "Permission to add items" +msgstr "" + +#: users/models.py:216 +msgid "Change" +msgstr "" + +#: users/models.py:216 +msgid "Permissions to edit items" +msgstr "" + +#: users/models.py:218 +msgid "Permission to delete items" +msgstr "" From 0974fde59e5a5f18fa2f21f3399a71cb8dcc39e2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 00:34:24 +1000 Subject: [PATCH 19/37] Add sqlite-config file back in - required for CI steps - might refactor this out later on --- docker/sqlite-config.env | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docker/sqlite-config.env diff --git a/docker/sqlite-config.env b/docker/sqlite-config.env new file mode 100644 index 0000000000..b41660ad6e --- /dev/null +++ b/docker/sqlite-config.env @@ -0,0 +1,10 @@ +# InvenTree environment variables for a development setup + +# Set DEBUG to False for a production environment! +INVENTREE_DEBUG=True +INVENTREE_DEBUG_LEVEL=INFO + +# Database configuration options +# Note: The example setup is for a PostgreSQL database (change as required) +INVENTREE_DB_ENGINE=sqlite +INVENTREE_DB_NAME=/home/inventree/dev/inventree_db.sqlite3 From ced9c6c050a74429e8dc4e4ce565634278295d9e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 01:02:55 +1000 Subject: [PATCH 20/37] Sqlite docker-compose file no longer requires .env file As this is only used for CI this is OK --- .github/workflows/docker_test.yaml | 4 ++++ docker/docker-compose.sqlite.yml | 12 ++++++------ docker/sqlite-config.env | 10 ---------- 3 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 docker/sqlite-config.env diff --git a/.github/workflows/docker_test.yaml b/.github/workflows/docker_test.yaml index d96621ee66..0865b0b0cf 100644 --- a/.github/workflows/docker_test.yaml +++ b/.github/workflows/docker_test.yaml @@ -14,6 +14,10 @@ on: branches: - 'master' - 'stable' + pull_request: + branches: + - 'master' + - 'stable' jobs: diff --git a/docker/docker-compose.sqlite.yml b/docker/docker-compose.sqlite.yml index e42c43a09c..0c08109af5 100644 --- a/docker/docker-compose.sqlite.yml +++ b/docker/docker-compose.sqlite.yml @@ -27,9 +27,9 @@ services: volumes: # Ensure you specify the location of the 'src' directory at the end of this file - src:/home/inventree - env_file: - # Environment variables required for the dev server are configured in dev-config.env - - sqlite-config.env + environment: + - INVENTREE_DEBUG=True + - INVENTREE_DB_ENGINE=sqlite restart: unless-stopped # Background worker process handles long-running or periodic tasks @@ -44,9 +44,9 @@ services: volumes: # Ensure you specify the location of the 'src' directory at the end of this file - src:/home/inventree - env_file: - # Environment variables required for the dev server are configured in dev-config.env - - sqlite-config.env + environment: + - INVENTREE_DEBUG=True + - INVENTREE_DB_ENGINE=sqlite restart: unless-stopped volumes: diff --git a/docker/sqlite-config.env b/docker/sqlite-config.env deleted file mode 100644 index b41660ad6e..0000000000 --- a/docker/sqlite-config.env +++ /dev/null @@ -1,10 +0,0 @@ -# InvenTree environment variables for a development setup - -# Set DEBUG to False for a production environment! -INVENTREE_DEBUG=True -INVENTREE_DEBUG_LEVEL=INFO - -# Database configuration options -# Note: The example setup is for a PostgreSQL database (change as required) -INVENTREE_DB_ENGINE=sqlite -INVENTREE_DB_NAME=/home/inventree/dev/inventree_db.sqlite3 From a3766250887050ddd7e460b1c274760a1d4dcb23 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 01:04:46 +1000 Subject: [PATCH 21/37] Force INVENTREE_DB_USER and INVENTREE_DB_PASSWORD to be set manually - Only for the "production" docker setup --- docker/production/.env | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docker/production/.env b/docker/production/.env index b1c9430b51..d1fca305d1 100644 --- a/docker/production/.env +++ b/docker/production/.env @@ -22,8 +22,11 @@ INVENTREE_DB_ENGINE=postgresql INVENTREE_DB_NAME=inventree INVENTREE_DB_HOST=inventree-db INVENTREE_DB_PORT=5432 -INVENTREE_DB_USER=pguser -INVENTREE_DB_PASSWORD=pgpassword + +# Database credentials - These must be configured before running +# Uncomment the lines below, and change from the default values! +#INVENTREE_DB_USER=pguser +#INVENTREE_DB_PASSWORD=pgpassword # Enable plugins? INVENTREE_PLUGINS_ENABLED=False From 1ac8ae76975f10c41a9e4f2d734621bc1912eafb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 01:10:29 +1000 Subject: [PATCH 22/37] No need to build docker test image on each pull request commit --- .github/workflows/docker_test.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/docker_test.yaml b/.github/workflows/docker_test.yaml index 0865b0b0cf..d96621ee66 100644 --- a/.github/workflows/docker_test.yaml +++ b/.github/workflows/docker_test.yaml @@ -14,10 +14,6 @@ on: branches: - 'master' - 'stable' - pull_request: - branches: - - 'master' - - 'stable' jobs: From 67196b866e6db5023d73f38d2a4b7bb87a078c1a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 01:13:34 +1000 Subject: [PATCH 23/37] Compose script fixes - Define INVENTREE_DB_NAME - Cache built image --- docker/docker-compose.sqlite.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docker/docker-compose.sqlite.yml b/docker/docker-compose.sqlite.yml index 0c08109af5..9800788b1d 100644 --- a/docker/docker-compose.sqlite.yml +++ b/docker/docker-compose.sqlite.yml @@ -21,6 +21,8 @@ services: build: context: . target: dev + # Cache the built image to be used by the inventree-dev-worker process + image: inventree-dev-image ports: # Expose web server on port 8000 - 8000:8000 @@ -30,14 +32,13 @@ services: environment: - INVENTREE_DEBUG=True - INVENTREE_DB_ENGINE=sqlite + - INVENTREE_DB_NAME=/home/inventree/db.sqlite3 restart: unless-stopped # Background worker process handles long-running or periodic tasks inventree-dev-worker: container_name: inventree-dev-worker - build: - context: . - target: dev + image: inventree-dev-image command: invoke worker depends_on: - inventree-dev-server @@ -47,6 +48,7 @@ services: environment: - INVENTREE_DEBUG=True - INVENTREE_DB_ENGINE=sqlite + - INVENTREE_DB_NAME=/home/inventree/db.sqlite3 restart: unless-stopped volumes: @@ -59,4 +61,4 @@ volumes: o: bind # This directory specified where InvenTree source code is stored "outside" the docker containers # By default, this directory is one level above the "docker" directory - device: ../ + device: ${INVENTREE_EXT_VOLUME:-../} From 27c807492d429402500f898921f2ed7b43bf04f2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 21 Apr 2022 11:45:09 +1000 Subject: [PATCH 24/37] Security patch for django --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 640eb497dd..9aef6607d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Please keep this list sorted -Django==3.2.12 # Django package +Django==3.2.13 # Django package bleach==4.1.0 # HTML santization certifi # Certifi is (most likely) installed through one of the requirements above coreapi==2.3.0 # API documentation @@ -12,7 +12,7 @@ django-allauth-2fa==0.8 # MFA / 2FA django-cleanup==5.1.0 # Manage deletion of old / unused uploaded files django-cors-headers==3.2.0 # CORS headers extension for DRF django-crispy-forms==1.11.2 # Form helpers -django-debug-toolbar==2.2 # Debug / profiling toolbar +django-debug-toolbar==3.2.4 # Debug / profiling toolbar django-error-report==0.2.0 # Error report viewer for the admin interface django-filter==2.4.0 # Extended filtering options django-formtools==2.3 # Form wizard tools From 6d56dbd2664d2cc361120a5191dccc116bd18cbf Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 21 Apr 2022 12:04:05 +1000 Subject: [PATCH 25/37] Adds project names for docker-compose files --- docker/.env | 1 + docker/production/.env | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docker/.env b/docker/.env index 2c33931c0c..54e37ea7a0 100644 --- a/docker/.env +++ b/docker/.env @@ -16,3 +16,4 @@ INVENTREE_DB_PASSWORD=pgpassword # Enable plugins? INVENTREE_PLUGINS_ENABLED=True +COMPOSE_PROJECT_NAME=inventree-development diff --git a/docker/production/.env b/docker/production/.env index d1fca305d1..220952bf23 100644 --- a/docker/production/.env +++ b/docker/production/.env @@ -30,3 +30,5 @@ INVENTREE_DB_PORT=5432 # Enable plugins? INVENTREE_PLUGINS_ENABLED=False + +COMPOSE_PROJECT_NAME=inventree-production From 0cd5a2b0055a3d522d5c568eaf57d0c77c5564f9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 21 Apr 2022 20:17:12 +1000 Subject: [PATCH 26/37] Revert location of init.sh for Dockerfile --- docker/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b272683322..9978460e8f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -110,8 +110,7 @@ RUN pip3 install --user --no-cache-dir --disable-pip-version-check -r ${INVENTRE WORKDIR ${INVENTREE_MNG_DIR} # Server init entrypoint -COPY init.sh ${INVENTREE_HOME}/init.sh -ENTRYPOINT ["/bin/bash", "${INVENTREE_HOME}/init.sh"] +ENTRYPOINT ["/bin/bash", "../docker/init.sh"] # Launch the production server # TODO: Work out why environment variables cannot be interpolated in this command From 9a9ed5f192df804878a90daae745b5ba352af379 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:36:30 +1000 Subject: [PATCH 27/37] Fix validation of duplicate IPN - Duplicate IPN check does not apply if an empty IPN value is set - Note that "if x" is a more pythonic test than "if x not in [None, '']" --- InvenTree/part/models.py | 7 ++++++- InvenTree/stock/models.py | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index b7269f3e5e..35872c09ba 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -777,7 +777,8 @@ class Part(MPTTModel): # User can decide whether duplicate IPN (Internal Part Number) values are allowed allow_duplicate_ipn = common.models.InvenTreeSetting.get_setting('PART_ALLOW_DUPLICATE_IPN') - if self.IPN is not None and not allow_duplicate_ipn: + # Raise an error if an IPN is set, and it is a duplicate + if self.IPN and not allow_duplicate_ipn: parts = Part.objects.filter(IPN__iexact=self.IPN) parts = parts.exclude(pk=self.pk) @@ -798,6 +799,10 @@ class Part(MPTTModel): super().clean() + # Strip IPN field + if self.IPN: + self.IPN = self.IPN.strip() + if self.trackable: for part in self.get_used_in().all(): diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 43593d3283..12131b5b58 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -453,10 +453,12 @@ class StockItem(MPTTModel): super().clean() - if self.serial is not None and type(self.serial) is str: + # Strip serial number field + if self.serial: self.serial = self.serial.strip() - if self.batch is not None and type(self.batch) is str: + # Strip batch code field + if self.batch: self.batch = self.batch.strip() try: From a7c18891b553936a3c5b8afad003a201e80dbc4a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:38:08 +1000 Subject: [PATCH 28/37] Increase unit testing for duplicate IPN testing - IPN duplication test is case sensitive! --- InvenTree/part/models.py | 2 +- InvenTree/part/test_part.py | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 35872c09ba..7973e408ce 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -779,7 +779,7 @@ class Part(MPTTModel): # Raise an error if an IPN is set, and it is a duplicate if self.IPN and not allow_duplicate_ipn: - parts = Part.objects.filter(IPN__iexact=self.IPN) + parts = Part.objects.filter(IPN=self.IPN) parts = parts.exclude(pk=self.pk) if parts.exists(): diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 040b2c9e68..889259d183 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -348,6 +348,26 @@ class PartSettingsTest(TestCase): with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='C') part.full_clean() + + # Any duplicate IPN should raise an error + Part.objects.create(name='xyz', revision='1', description='A part', IPN='UNIQUE') + + # Case sensitive, so other variations don't error out: + Part.objects.create(name='xyz', revision='2', description='A part', IPN='UNIQUe') + Part.objects.create(name='xyz', revision='3', description='A part', IPN='UNIQuE') + Part.objects.create(name='xyz', revision='4', description='A part', IPN='UNIqUE') + + with self.assertRaises(ValidationError): + Part.objects.create(name='zyx', description='A part', IPN='UNIQUE') + + # However, *blank* / empty IPN values should be allowed, even if duplicates are not + # Note that leading / trailling whitespace characters are trimmed, too + Part.objects.create(name='abc', revision='1', description='A part', IPN=None) + Part.objects.create(name='abc', revision='2', description='A part', IPN='') + Part.objects.create(name='abc', revision='3', description='A part', IPN=None) + Part.objects.create(name='abc', revision='4', description='A part', IPN=' ') + Part.objects.create(name='abc', revision='5', description='A part', IPN=' ') + Part.objects.create(name='abc', revision='6', description='A part', IPN=' ') class PartSubscriptionTests(TestCase): From aa4df62ac97ce4eb639b03b3e6b82d892d52e728 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 00:40:23 +1000 Subject: [PATCH 29/37] IPN fix --- InvenTree/part/test_part.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 889259d183..cb932993dc 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -348,7 +348,7 @@ class PartSettingsTest(TestCase): with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='C') part.full_clean() - + # Any duplicate IPN should raise an error Part.objects.create(name='xyz', revision='1', description='A part', IPN='UNIQUE') From 292d28d3786c6d8179736db51f029f54ef3afb80 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 01:00:02 +1000 Subject: [PATCH 30/37] Account for cases where serial number could be an integer! --- InvenTree/stock/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 12131b5b58..fa343e9a9c 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -454,11 +454,11 @@ class StockItem(MPTTModel): super().clean() # Strip serial number field - if self.serial: + if type(self.serial) is str: self.serial = self.serial.strip() # Strip batch code field - if self.batch: + if type(self.batch) is str: self.batch = self.batch.strip() try: From 5fde9f552c8792b3889401f51eff545e6466e129 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 22 Apr 2022 01:00:38 +1000 Subject: [PATCH 31/37] Add similar check for IPN --- InvenTree/part/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 7973e408ce..1cb83b839a 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -800,7 +800,7 @@ class Part(MPTTModel): super().clean() # Strip IPN field - if self.IPN: + if type(self.IPN) is str: self.IPN = self.IPN.strip() if self.trackable: From dc0f18d21fdacaf30c1693c06984b99d9128fdf4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 11:20:49 +1000 Subject: [PATCH 32/37] Specify charset and collation options for the test database --- InvenTree/InvenTree/settings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 5b3d2eb8d8..c7e058b26c 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -546,6 +546,12 @@ if "sqlite" in db_engine: # Provide OPTIONS dict back to the database configuration dict db_config['OPTIONS'] = db_options +# Set testing options for the database +db_config['TEST'] = { + 'CHARSET': 'utf8', + 'COLLATION': 'utf8_general_ci', +} + DATABASES = { 'default': db_config } From 2f1e869351f27556cb0451882b4ee625bbcf0a7d Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 11:31:51 +1000 Subject: [PATCH 33/37] Only set collation option for mysql test database --- InvenTree/InvenTree/settings.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index c7e058b26c..e1c584362f 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -549,14 +549,16 @@ db_config['OPTIONS'] = db_options # Set testing options for the database db_config['TEST'] = { 'CHARSET': 'utf8', - 'COLLATION': 'utf8_general_ci', } +# Set collation option for mysql test database +if 'mysql' in db_engine: + db_config['TEST']['COLLATION'] = 'utf8_general_ci' + DATABASES = { 'default': db_config } - _cache_config = CONFIG.get("cache", {}) _cache_host = _cache_config.get("host", os.getenv("INVENTREE_CACHE_HOST")) _cache_port = _cache_config.get( From 0806e18aca85590aff900ce11edd8e8ec1da6b58 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 12:39:42 +1000 Subject: [PATCH 34/37] Case sensitive collation --- InvenTree/InvenTree/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index e1c584362f..1d80250fb3 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -553,7 +553,7 @@ db_config['TEST'] = { # Set collation option for mysql test database if 'mysql' in db_engine: - db_config['TEST']['COLLATION'] = 'utf8_general_ci' + db_config['TEST']['COLLATION'] = 'utf8' DATABASES = { 'default': db_config From fa3c24b085fff8b7ab765ab74c37b6272f32460f Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 13:25:22 +1000 Subject: [PATCH 35/37] Try a different collation option --- InvenTree/InvenTree/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 1d80250fb3..27553767d7 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -553,7 +553,7 @@ db_config['TEST'] = { # Set collation option for mysql test database if 'mysql' in db_engine: - db_config['TEST']['COLLATION'] = 'utf8' + db_config['TEST']['COLLATION'] = 'utf8mb4' DATABASES = { 'default': db_config From 49949201199b3ffa73d0051c1b3aad6ddb596370 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 13:48:15 +1000 Subject: [PATCH 36/37] Use recommended collation option --- InvenTree/InvenTree/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 27553767d7..c34f101180 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -553,7 +553,8 @@ db_config['TEST'] = { # Set collation option for mysql test database if 'mysql' in db_engine: - db_config['TEST']['COLLATION'] = 'utf8mb4' + # Ref: https://docs.djangoproject.com/en/4.0/ref/databases/#collation-settings + db_config['TEST']['COLLATION'] = 'utf8_bin' DATABASES = { 'default': db_config From 99718865c0dd8ceca179d42ed6313a45e56379bf Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 22 Apr 2022 14:33:46 +1000 Subject: [PATCH 37/37] Further attempts to fix CI issues --- InvenTree/InvenTree/settings.py | 3 +-- InvenTree/part/models.py | 2 +- InvenTree/part/test_part.py | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index c34f101180..e1c584362f 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -553,8 +553,7 @@ db_config['TEST'] = { # Set collation option for mysql test database if 'mysql' in db_engine: - # Ref: https://docs.djangoproject.com/en/4.0/ref/databases/#collation-settings - db_config['TEST']['COLLATION'] = 'utf8_bin' + db_config['TEST']['COLLATION'] = 'utf8_general_ci' DATABASES = { 'default': db_config diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 1cb83b839a..d6ca9f650c 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -779,7 +779,7 @@ class Part(MPTTModel): # Raise an error if an IPN is set, and it is a duplicate if self.IPN and not allow_duplicate_ipn: - parts = Part.objects.filter(IPN=self.IPN) + parts = Part.objects.filter(IPN__iexact=self.IPN) parts = parts.exclude(pk=self.pk) if parts.exists(): diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index cb932993dc..811acebc69 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -352,10 +352,10 @@ class PartSettingsTest(TestCase): # Any duplicate IPN should raise an error Part.objects.create(name='xyz', revision='1', description='A part', IPN='UNIQUE') - # Case sensitive, so other variations don't error out: - Part.objects.create(name='xyz', revision='2', description='A part', IPN='UNIQUe') - Part.objects.create(name='xyz', revision='3', description='A part', IPN='UNIQuE') - Part.objects.create(name='xyz', revision='4', description='A part', IPN='UNIqUE') + # Case insensitive, so variations on spelling should throw an error + for ipn in ['UNiquE', 'uniQuE', 'unique']: + with self.assertRaises(ValidationError): + Part.objects.create(name='xyz', revision='2', description='A part', IPN=ipn) with self.assertRaises(ValidationError): Part.objects.create(name='zyx', description='A part', IPN='UNIQUE')