diff --git a/InvenTree/InvenTree/middleware.py b/InvenTree/InvenTree/middleware.py
index 37b9a27c63..2f1cf3a157 100644
--- a/InvenTree/InvenTree/middleware.py
+++ b/InvenTree/InvenTree/middleware.py
@@ -47,7 +47,12 @@ class AuthRequiredMiddleware(object):
authorized = False
- if 'Authorization' in request.headers.keys():
+ # Allow static files to be accessed without auth
+ # Important for e.g. login page
+ if request.path_info.startswith('/static/'):
+ authorized = True
+
+ elif 'Authorization' in request.headers.keys():
auth = request.headers['Authorization'].strip()
if auth.startswith('Token') and len(auth.split()) == 2:
@@ -56,7 +61,7 @@ class AuthRequiredMiddleware(object):
# Does the provided token match a valid user?
if Token.objects.filter(key=token).exists():
- allowed = ['/api/', '/media/', '/static/']
+ allowed = ['/api/', '/media/']
# Only allow token-auth for /media/ or /static/ dirs!
if any([request.path_info.startswith(a) for a in allowed]):
diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css
index 78c1808adf..50a24aa095 100644
--- a/InvenTree/InvenTree/static/css/inventree.css
+++ b/InvenTree/InvenTree/static/css/inventree.css
@@ -11,6 +11,45 @@
--label-yellow: #fdc82a;
}
+.login-screen {
+ background-image: url("/static/img/paper_splash.jpg");
+ background-size: cover;
+ background-repeat: no-repeat;
+ height: 100%;
+ font-family: 'Numans', sans-serif;
+ color: #eee;
+}
+
+.login-container {
+ left: 50%;
+ position: fixed;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ width: 30%;
+ align-content: center;
+ border-radius: 15px;
+ padding: 20px;
+ padding-bottom: 35px;
+ background-color: rgba(50, 50, 50, 0.75);
+}
+
+.login-header {
+ padding-right: 30px;
+ margin-right: 30px;
+}
+
+.login-container input {
+ background-color: rgba(250, 250, 250, 0.9);
+}
+
+.login-button {
+ background-color: rgba(250, 250, 250, 0.9);
+ color: #333;
+ border-color: #AAA;
+ width: 100%;
+ border-radius: 5px;
+}
+
.markdownx .row {
margin: 5px;
padding: 5px;
@@ -268,6 +307,10 @@
font-style: italic;
}
+.rowinherited {
+ background-color: #dde;
+}
+
.dropdown {
padding-left: 1px;
margin-left: 1px;
@@ -574,7 +617,7 @@
margin-bottom: 3px;
}
-.modal-form-content {
+.modal-form-content-wrapper {
border-radius: 0;
position:relative;
height: auto !important;
@@ -708,13 +751,6 @@ input[type="submit"] {
color: #e00;
}
-.login {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
-}
-
.part-allocation {
padding: 3px 10px;
border: 1px solid #ccc;
diff --git a/InvenTree/InvenTree/static/img/paper_splash.jpg b/InvenTree/InvenTree/static/img/paper_splash.jpg
new file mode 100644
index 0000000000..e466708f3f
Binary files /dev/null and b/InvenTree/InvenTree/static/img/paper_splash.jpg differ
diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py
index 136d21d553..061ae0d16d 100644
--- a/InvenTree/build/forms.py
+++ b/InvenTree/build/forms.py
@@ -39,6 +39,11 @@ class EditBuildForm(HelperForm):
help_text=_('Target date for build completion. Build will be overdue after this date.')
)
+ quantity = RoundingDecimalFormField(
+ max_digits=10, decimal_places=5,
+ help_text=_('Number of items to build')
+ )
+
class Meta:
model = Build
fields = [
@@ -53,6 +58,8 @@ class EditBuildForm(HelperForm):
'parent',
'sales_order',
'link',
+ 'issued_by',
+ 'responsible',
]
diff --git a/InvenTree/build/migrations/0026_auto_20210216_1539.py b/InvenTree/build/migrations/0026_auto_20210216_1539.py
new file mode 100644
index 0000000000..aee7c44bd6
--- /dev/null
+++ b/InvenTree/build/migrations/0026_auto_20210216_1539.py
@@ -0,0 +1,27 @@
+# Generated by Django 3.0.7 on 2021-02-16 04:39
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('users', '0005_owner_model'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('build', '0025_build_target_date'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='build',
+ name='issued_by',
+ field=models.ForeignKey(blank=True, help_text='User who issued this build order', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='builds_issued', to=settings.AUTH_USER_MODEL),
+ ),
+ migrations.AddField(
+ model_name='build',
+ name='responsible',
+ field=models.ForeignKey(blank=True, help_text='User responsible for this build order', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='builds_responsible', to='users.Owner'),
+ ),
+ ]
diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py
index c1d4aa8026..ae7ea14ece 100644
--- a/InvenTree/build/models.py
+++ b/InvenTree/build/models.py
@@ -23,7 +23,7 @@ from markdownx.models import MarkdownxField
from mptt.models import MPTTModel, TreeForeignKey
from InvenTree.status_codes import BuildStatus
-from InvenTree.helpers import increment, getSetting, normalize
+from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode
from InvenTree.validators import validate_build_order_reference
from InvenTree.models import InvenTreeAttachment
@@ -33,6 +33,7 @@ import InvenTree.fields
from stock import models as StockModels
from part import models as PartModels
+from users import models as UserModels
class Build(MPTTModel):
@@ -53,6 +54,9 @@ class Build(MPTTModel):
completion_date: Date the build was completed (or, if incomplete, the expected date of completion)
link: External URL for extra information
notes: Text notes
+ completed_by: User that completed the build
+ issued_by: User that issued the build
+ responsible: User (or group) responsible for completing the build
"""
OVERDUE_FILTER = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
@@ -61,6 +65,20 @@ class Build(MPTTModel):
verbose_name = _("Build Order")
verbose_name_plural = _("Build Orders")
+ def format_barcode(self, **kwargs):
+ """
+ Return a JSON string to represent this build as a barcode
+ """
+
+ return MakeBarcode(
+ "buildorder",
+ self.pk,
+ {
+ "reference": self.title,
+ "url": self.get_absolute_url(),
+ }
+ )
+
@staticmethod
def filterByDate(queryset, min_date, max_date):
"""
@@ -214,6 +232,22 @@ class Build(MPTTModel):
blank=True, null=True,
related_name='builds_completed'
)
+
+ issued_by = models.ForeignKey(
+ User,
+ on_delete=models.SET_NULL,
+ blank=True, null=True,
+ help_text=_('User who issued this build order'),
+ related_name='builds_issued',
+ )
+
+ responsible = models.ForeignKey(
+ UserModels.Owner,
+ on_delete=models.SET_NULL,
+ blank=True, null=True,
+ help_text=_('User responsible for this build order'),
+ related_name='builds_responsible',
+ )
link = InvenTree.fields.InvenTreeURLField(
verbose_name=_('External Link'),
diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html
index 9ca3fff818..fab9eb8353 100644
--- a/InvenTree/build/templates/build/build_base.html
+++ b/InvenTree/build/templates/build/build_base.html
@@ -45,27 +45,35 @@ src="{% static 'img/blank_image.png' %}"
{{ build.title }}
-
-
+
+
+
+
+ |
+ {% trans "Created" %} |
+ {{ build.creation_date }} |
+
+
+ |
+ {% trans "Target Date" %} |
+ {% if build.target_date %}
+
+ {{ build.target_date }}{% if build.is_overdue %} {% endif %}
+ |
+ {% else %}
+ {% trans "No target date set" %} |
+ {% endif %}
+
+
+ |
+ {% trans "Completed" %} |
+ {% if build.completion_date %}
+ {{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %} |
+ {% else %}
+ {% trans "Build not complete" %} |
+ {% endif %}
+
diff --git a/InvenTree/build/templates/build/index.html b/InvenTree/build/templates/build/index.html
index 37993107a7..05864cd780 100644
--- a/InvenTree/build/templates/build/index.html
+++ b/InvenTree/build/templates/build/index.html
@@ -22,19 +22,33 @@ InvenTree | {% trans "Build Orders" %}
@@ -157,17 +171,29 @@ $("#view-list").click(function() {
$("#view-calendar").show();
});
- $("#collapse-item-active").collapse().show();
+$("#collapse-item-active").collapse().show();
- $("#new-build").click(function() {
- newBuildOrder();
+$("#new-build").click(function() {
+ newBuildOrder();
+});
+
+loadBuildTable($("#build-table"), {
+ url: "{% url 'api-build-list' %}",
+ params: {
+ part_detail: "true",
+ },
+});
+
+$('#multi-build-print').click(function() {
+ var rows = $("#build-table").bootstrapTable('getSelections');
+
+ var build_ids = [];
+
+ rows.forEach(function(row) {
+ build_ids.push(row.pk);
});
- loadBuildTable($("#build-table"), {
- url: "{% url 'api-build-list' %}",
- params: {
- part_detail: "true",
- },
- });
+ printBuildReports(build_ids);
+});
{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py
index 0887c49397..3c4b94c43d 100644
--- a/InvenTree/build/views.py
+++ b/InvenTree/build/views.py
@@ -675,6 +675,13 @@ class BuildCreate(AjaxCreateView):
initials = super(BuildCreate, self).get_initial().copy()
+ initials['parent'] = self.request.GET.get('parent', None)
+
+ # User has provided a SalesOrder ID
+ initials['sales_order'] = self.request.GET.get('sales_order', None)
+
+ initials['quantity'] = self.request.GET.get('quantity', 1)
+
part = self.request.GET.get('part', None)
if part:
@@ -684,17 +691,20 @@ class BuildCreate(AjaxCreateView):
# User has provided a Part ID
initials['part'] = part
initials['destination'] = part.get_default_location()
+
+ to_order = part.quantity_to_order
+
+ if to_order < 1:
+ to_order = 1
+
+ initials['quantity'] = to_order
except (ValueError, Part.DoesNotExist):
pass
initials['reference'] = Build.getNextBuildNumber()
- initials['parent'] = self.request.GET.get('parent', None)
-
- # User has provided a SalesOrder ID
- initials['sales_order'] = self.request.GET.get('sales_order', None)
-
- initials['quantity'] = self.request.GET.get('quantity', 1)
+ # Pre-fill the issued_by user
+ initials['issued_by'] = self.request.user
return initials
diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py
index 9e6c6e868d..d893206126 100644
--- a/InvenTree/common/models.py
+++ b/InvenTree/common/models.py
@@ -18,7 +18,7 @@ from djmoney.contrib.exchange.models import convert_money
from djmoney.contrib.exchange.exceptions import MissingRate
from django.utils.translation import ugettext as _
-from django.core.validators import MinValueValidator
+from django.core.validators import MinValueValidator, URLValidator
from django.core.exceptions import ValidationError
import InvenTree.helpers
@@ -64,6 +64,13 @@ class InvenTreeSetting(models.Model):
'default': 'My company name',
},
+ 'INVENTREE_BASE_URL': {
+ 'name': _('Base URL'),
+ 'description': _('Base URL for server instance'),
+ 'validator': URLValidator(),
+ 'default': '',
+ },
+
'INVENTREE_DEFAULT_CURRENCY': {
'name': _('Default Currency'),
'description': _('Default currency'),
@@ -528,6 +535,11 @@ class InvenTreeSetting(models.Model):
return
+ if callable(validator):
+ # We can accept function validators with a single argument
+ print("Running validator function")
+ validator(self.value)
+
# Boolean validator
if validator == bool:
# Value must "look like" a boolean value
diff --git a/InvenTree/label/api.py b/InvenTree/label/api.py
index 6b542f80ed..b2bfe9164f 100644
--- a/InvenTree/label/api.py
+++ b/InvenTree/label/api.py
@@ -5,6 +5,7 @@ import sys
from django.utils.translation import ugettext as _
from django.conf.urls import url, include
+from django.core.exceptions import ValidationError, FieldError
from django_filters.rest_framework import DjangoFilterBackend
@@ -119,13 +120,20 @@ class StockItemLabelList(LabelListView, StockItemLabelMixin):
matches = True
# Filter string defined for the StockItemLabel object
- filters = InvenTree.helpers.validateFilterString(label.filters)
+ try:
+ filters = InvenTree.helpers.validateFilterString(label.filters)
+ except ValidationError:
+ continue
for item in items:
item_query = StockItem.objects.filter(pk=item.pk)
- if not item_query.filter(**filters).exists():
+ try:
+ if not item_query.filter(**filters).exists():
+ matches = False
+ break
+ except FieldError:
matches = False
break
@@ -273,13 +281,21 @@ class StockLocationLabelList(LabelListView, StockLocationLabelMixin):
matches = True
# Filter string defined for the StockLocationLabel object
- filters = InvenTree.helpers.validateFilterString(label.filters)
+ try:
+ filters = InvenTree.helpers.validateFilterString(label.filters)
+ except:
+ # Skip if there was an error validating the filters...
+ continue
for loc in locations:
loc_query = StockLocation.objects.filter(pk=loc.pk)
- if not loc_query.filter(**filters).exists():
+ try:
+ if not loc_query.filter(**filters).exists():
+ matches = False
+ break
+ except FieldError:
matches = False
break
diff --git a/InvenTree/label/models.py b/InvenTree/label/models.py
index a34aa3831d..9a98810d28 100644
--- a/InvenTree/label/models.py
+++ b/InvenTree/label/models.py
@@ -12,6 +12,7 @@ from blabel import LabelWriter
from django.db import models
from django.core.validators import FileExtensionValidator
+from django.core.exceptions import ValidationError, FieldError
from django.utils.translation import gettext_lazy as _
@@ -145,9 +146,12 @@ class StockItemLabel(LabelTemplate):
Test if this label template matches a given StockItem object
"""
- filters = validateFilterString(self.filters)
-
- items = stock.models.StockItem.objects.filter(**filters)
+ try:
+ filters = validateFilterString(self.filters)
+ items = stock.models.StockItem.objects.filter(**filters)
+ except (ValidationError, FieldError):
+ # If an error exists with the "filters" field, return False
+ return False
items = items.filter(pk=item.pk)
@@ -198,9 +202,11 @@ class StockLocationLabel(LabelTemplate):
Test if this label template matches a given StockLocation object
"""
- filters = validateFilterString(self.filters)
-
- locs = stock.models.StockLocation.objects.filter(**filters)
+ try:
+ filters = validateFilterString(self.filters)
+ locs = stock.models.StockLocation.objects.filter(**filters)
+ except (ValidationError, FieldError):
+ return False
locs = locs.filter(pk=location.pk)
diff --git a/InvenTree/locale/de/LC_MESSAGES/django.mo b/InvenTree/locale/de/LC_MESSAGES/django.mo
index b2a1691aac..4e3840173b 100644
Binary files a/InvenTree/locale/de/LC_MESSAGES/django.mo and b/InvenTree/locale/de/LC_MESSAGES/django.mo differ
diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po
index 68126b7966..444541e145 100644
--- a/InvenTree/locale/de/LC_MESSAGES/django.po
+++ b/InvenTree/locale/de/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-01-29 12:04+1100\n"
+"POT-Creation-Date: 2021-02-16 22:33+1100\n"
"PO-Revision-Date: 2020-05-03 11:32+0200\n"
"Last-Translator: Christian Schlüter
\n"
"Language-Team: C \n"
@@ -31,7 +31,7 @@ msgstr "Keine passende Aktion gefunden"
msgid "Enter date"
msgstr "Eintrags-Notizen"
-#: InvenTree/forms.py:110 build/forms.py:90 build/forms.py:178
+#: InvenTree/forms.py:110 build/forms.py:92 build/forms.py:180
msgid "Confirm"
msgstr "Bestätigen"
@@ -105,12 +105,14 @@ msgstr "Datei zum Anhängen auswählen"
msgid "File comment"
msgstr "Datei-Kommentar"
-#: InvenTree/models.py:68 templates/js/stock.js:919
+#: InvenTree/models.py:68
+#: report/templates/report/inventree_test_report_base.html:91
+#: templates/js/stock.js:919
msgid "User"
msgstr "Benutzer"
-#: InvenTree/models.py:106 label/models.py:68 part/models.py:654
-#: part/templates/part/params.html:24 report/models.py:152
+#: InvenTree/models.py:106 label/models.py:69 part/models.py:654
+#: part/templates/part/params.html:24 report/models.py:162
#: templates/js/part.js:129
msgid "Name"
msgstr "Name"
@@ -121,23 +123,23 @@ msgstr "Name"
msgid "Description (optional)"
msgstr "Firmenbeschreibung"
-#: InvenTree/settings.py:454
+#: InvenTree/settings.py:446
msgid "English"
msgstr "Englisch"
-#: InvenTree/settings.py:455
+#: InvenTree/settings.py:447
msgid "French"
msgstr "Französisch"
-#: InvenTree/settings.py:456
+#: InvenTree/settings.py:448
msgid "German"
msgstr "Deutsch"
-#: InvenTree/settings.py:457
+#: InvenTree/settings.py:449
msgid "Polish"
msgstr "Polnisch"
-#: InvenTree/settings.py:458
+#: InvenTree/settings.py:450
msgid "Turkish"
msgstr ""
@@ -274,7 +276,7 @@ msgstr "Teil auswählen"
msgid "Password fields must match"
msgstr ""
-#: InvenTree/views.py:795 templates/navbar.html:78
+#: InvenTree/views.py:795 templates/navbar.html:83
#, fuzzy
#| msgid "No user information"
msgid "System Information"
@@ -336,14 +338,14 @@ msgstr "Bestell-Referenz"
msgid "Order target date"
msgstr "Kein Ziel gesetzt"
-#: build/forms.py:39 build/models.py:206
+#: build/forms.py:39 build/models.py:210
msgid ""
"Target date for build completion. Build will be overdue after this date."
msgstr ""
-#: build/forms.py:78 build/templates/build/auto_allocate.html:17
-#: build/templates/build/build_base.html:83
-#: build/templates/build/detail.html:29 common/models.py:610
+#: build/forms.py:80 build/templates/build/auto_allocate.html:17
+#: build/templates/build/build_base.html:91
+#: build/templates/build/detail.html:29 common/models.py:647
#: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75
#: order/templates/order/order_wizard/select_parts.html:32
#: order/templates/order/purchase_order_detail.html:179
@@ -351,174 +353,181 @@ msgstr ""
#: order/templates/order/sales_order_detail.html:156
#: part/templates/part/allocation.html:16
#: part/templates/part/allocation.html:49
-#: part/templates/part/sale_prices.html:82 stock/forms.py:306
-#: stock/templates/stock/item_base.html:51
+#: part/templates/part/sale_prices.html:82
+#: report/templates/report/inventree_build_order_base.html:116
+#: report/templates/report/inventree_test_report_base.html:77
+#: stock/forms.py:306 stock/templates/stock/item_base.html:51
#: stock/templates/stock/item_base.html:57
-#: stock/templates/stock/item_base.html:238
+#: stock/templates/stock/item_base.html:234
#: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364
#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:910
#: templates/js/stock.js:1149
msgid "Quantity"
msgstr "Anzahl"
-#: build/forms.py:79
+#: build/forms.py:81
#, fuzzy
#| msgid "Serial number for this item"
msgid "Enter quantity for build output"
msgstr "Seriennummer für dieses Teil"
-#: build/forms.py:83 stock/forms.py:117
+#: build/forms.py:85 stock/forms.py:117
#, fuzzy
#| msgid "Serial Number"
msgid "Serial numbers"
msgstr "Seriennummer"
-#: build/forms.py:85
+#: build/forms.py:87
#, fuzzy
#| msgid "Serial number for this item"
msgid "Enter serial numbers for build outputs"
msgstr "Seriennummer für dieses Teil"
-#: build/forms.py:91
+#: build/forms.py:93
#, fuzzy
#| msgid "Confirm completion of build"
msgid "Confirm creation of build outut"
msgstr "Baufertigstellung bestätigen"
-#: build/forms.py:111
+#: build/forms.py:113
#, fuzzy
#| msgid "Confirm completion of build"
msgid "Confirm deletion of build output"
msgstr "Baufertigstellung bestätigen"
-#: build/forms.py:132
+#: build/forms.py:134
#, fuzzy
#| msgid "Confirm unallocation of build stock"
msgid "Confirm unallocation of stock"
msgstr "Zuweisungsaufhebung bestätigen"
-#: build/forms.py:156
+#: build/forms.py:158
msgid "Confirm stock allocation"
msgstr "Lagerbestandszuordnung bestätigen"
-#: build/forms.py:179
+#: build/forms.py:181
#, fuzzy
#| msgid "Mark order as complete"
msgid "Mark build as complete"
msgstr "Bestellung als vollständig markieren"
-#: build/forms.py:203
+#: build/forms.py:205
#, fuzzy
#| msgid "Location Details"
msgid "Location of completed parts"
msgstr "Standort-Details"
-#: build/forms.py:208
+#: build/forms.py:210
#, fuzzy
#| msgid "Confirm stock allocation"
msgid "Confirm completion with incomplete stock allocation"
msgstr "Lagerbestandszuordnung bestätigen"
-#: build/forms.py:211
+#: build/forms.py:213
msgid "Confirm build completion"
msgstr "Bau-Fertigstellung bestätigen"
-#: build/forms.py:231 build/views.py:68
+#: build/forms.py:233 build/views.py:68
msgid "Confirm build cancellation"
msgstr "Bauabbruch bestätigen"
-#: build/forms.py:245
+#: build/forms.py:247
#, fuzzy
#| msgid "Select stock item to allocate"
msgid "Select quantity of stock to allocate"
msgstr "Lagerobjekt für Zuordnung auswählen"
-#: build/models.py:61 build/templates/build/build_base.html:8
+#: build/models.py:65 build/templates/build/build_base.html:8
#: build/templates/build/build_base.html:35
#: part/templates/part/allocation.html:20
+#: report/templates/report/inventree_build_order_base.html:108
msgid "Build Order"
msgstr "Bauauftrag"
-#: build/models.py:62 build/templates/build/index.html:8
+#: build/models.py:66 build/templates/build/index.html:8
#: build/templates/build/index.html:15 order/templates/order/so_builds.html:11
#: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31
-#: templates/InvenTree/settings/tabs.html:28 users/models.py:36
+#: templates/InvenTree/settings/tabs.html:31 users/models.py:36
msgid "Build Orders"
msgstr "Bauaufträge"
-#: build/models.py:108
+#: build/models.py:112
#, fuzzy
#| msgid "Order Reference"
msgid "Build Order Reference"
msgstr "Bestellreferenz"
-#: build/models.py:109 order/templates/order/purchase_order_detail.html:174
+#: build/models.py:113 order/templates/order/purchase_order_detail.html:174
#: templates/js/bom.js:187 templates/js/build.js:509
msgid "Reference"
msgstr "Referenz"
-#: build/models.py:116 build/templates/build/detail.html:19
+#: build/models.py:120 build/templates/build/detail.html:19
#: company/models.py:359 company/templates/company/detail.html:23
#: company/templates/company/supplier_part_base.html:61
-#: company/templates/company/supplier_part_detail.html:27 label/models.py:75
+#: company/templates/company/supplier_part_detail.html:27 label/models.py:76
#: order/templates/order/purchase_order_detail.html:161 part/models.py:678
#: part/templates/part/detail.html:51 part/templates/part/set_category.html:14
-#: report/models.py:166 templates/InvenTree/search.html:147
+#: report/models.py:175
+#: report/templates/report/inventree_build_order_base.html:120
+#: templates/InvenTree/search.html:147
#: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180
-#: templates/js/bom.js:547 templates/js/build.js:664 templates/js/company.js:56
+#: templates/js/bom.js:547 templates/js/build.js:670 templates/js/company.js:56
#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188
#: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:586
#: templates/js/stock.js:512 templates/js/stock.js:891
msgid "Description"
msgstr "Beschreibung"
-#: build/models.py:119
+#: build/models.py:123
msgid "Brief description of the build"
msgstr "Kurze Beschreibung des Baus"
-#: build/models.py:128 build/templates/build/build_base.html:113
+#: build/models.py:132 build/templates/build/build_base.html:121
#: build/templates/build/detail.html:75
msgid "Parent Build"
msgstr "Eltern-Bau"
-#: build/models.py:129
+#: build/models.py:133
#, fuzzy
#| msgid "SalesOrder to which this build is allocated"
msgid "BuildOrder to which this build is allocated"
msgstr "Bestellung, die diesem Bau zugwiesen ist"
-#: build/models.py:134 build/templates/build/auto_allocate.html:16
-#: build/templates/build/build_base.html:78
+#: build/models.py:138 build/templates/build/auto_allocate.html:16
+#: build/templates/build/build_base.html:86
#: build/templates/build/detail.html:24 order/models.py:652
#: order/templates/order/order_wizard/select_parts.html:30
#: order/templates/order/purchase_order_detail.html:148
#: order/templates/order/receive_parts.html:19 part/models.py:320
#: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26
-#: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133
-#: templates/js/barcode.js:362 templates/js/bom.js:153 templates/js/bom.js:532
-#: templates/js/build.js:669 templates/js/company.js:138
-#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:486
+#: part/templates/part/set_category.html:13
+#: report/templates/report/inventree_build_order_base.html:112
+#: templates/InvenTree/search.html:133 templates/js/barcode.js:362
+#: templates/js/bom.js:153 templates/js/bom.js:532 templates/js/build.js:675
+#: templates/js/company.js:138 templates/js/part.js:252
+#: templates/js/part.js:357 templates/js/stock.js:486
#: templates/js/stock.js:1221
msgid "Part"
msgstr "Teil"
-#: build/models.py:142
+#: build/models.py:146
msgid "Select part to build"
msgstr "Teil für den Bau wählen"
-#: build/models.py:147
+#: build/models.py:151
msgid "Sales Order Reference"
msgstr "Bestellungsreferenz"
-#: build/models.py:151
+#: build/models.py:155
msgid "SalesOrder to which this build is allocated"
msgstr "Bestellung, die diesem Bau zugwiesen ist"
-#: build/models.py:156
+#: build/models.py:160
msgid "Source Location"
msgstr "Quell-Standort"
-#: build/models.py:160
+#: build/models.py:164
msgid ""
"Select location to take stock from for this build (leave blank to take from "
"any stock location)"
@@ -526,155 +535,167 @@ msgstr ""
"Lager-Entnahmestandort für diesen Bau wählen (oder leer lassen für einen "
"beliebigen Lager-Standort)"
-#: build/models.py:165
+#: build/models.py:169
#, fuzzy
#| msgid "Destination stock location"
msgid "Destination Location"
msgstr "Ziel-Lagerbestand"
-#: build/models.py:169
+#: build/models.py:173
msgid "Select location where the completed items will be stored"
msgstr ""
-#: build/models.py:173
+#: build/models.py:177
msgid "Build Quantity"
msgstr "Bau-Anzahl"
-#: build/models.py:176
+#: build/models.py:180
#, fuzzy
#| msgid "Number of parts to build"
msgid "Number of stock items to build"
msgstr "Anzahl der zu bauenden Teile"
-#: build/models.py:180
+#: build/models.py:184
#, fuzzy
#| msgid "Completed"
msgid "Completed items"
msgstr "Fertig"
-#: build/models.py:182
+#: build/models.py:186
#, fuzzy
#| msgid "Delete this Stock Item when stock is depleted"
msgid "Number of stock items which have been completed"
msgstr "Objekt löschen wenn Lagerbestand aufgebraucht"
-#: build/models.py:186 part/templates/part/part_base.html:158
+#: build/models.py:190 part/templates/part/part_base.html:157
msgid "Build Status"
msgstr "Bau-Status"
-#: build/models.py:190
+#: build/models.py:194
msgid "Build status code"
msgstr "Bau-Statuscode"
-#: build/models.py:194 stock/models.py:418
+#: build/models.py:198 stock/models.py:421
msgid "Batch Code"
msgstr "Losnummer"
-#: build/models.py:198
+#: build/models.py:202
msgid "Batch code for this build output"
msgstr "Chargennummer für diese Bau-Ausgabe"
-#: build/models.py:205 order/models.py:437
+#: build/models.py:209 order/models.py:437
msgid "Target completion date"
msgstr ""
-#: build/models.py:219 build/templates/build/detail.html:89
+#: build/models.py:226
+#, fuzzy
+#| msgid "This stock item is allocated to Sales Order"
+msgid "User who issued this build order"
+msgstr "Dieses Lagerobjekt ist dem Auftrag zugewiesen"
+
+#: build/models.py:234
+msgid "User responsible for this build order"
+msgstr ""
+
+#: build/models.py:239 build/templates/build/detail.html:89
#: company/templates/company/supplier_part_base.html:68
#: company/templates/company/supplier_part_detail.html:24
-#: part/templates/part/detail.html:80 part/templates/part/part_base.html:105
-#: stock/models.py:412 stock/templates/stock/item_base.html:321
+#: part/templates/part/detail.html:80 part/templates/part/part_base.html:104
+#: stock/models.py:415 stock/templates/stock/item_base.html:317
msgid "External Link"
msgstr "Externer Link"
-#: build/models.py:220 part/models.py:712 stock/models.py:414
+#: build/models.py:240 part/models.py:712 stock/models.py:417
msgid "Link to external URL"
msgstr "Link zu einer externen URL"
-#: build/models.py:224 build/templates/build/tabs.html:23 company/models.py:366
+#: build/models.py:244 build/templates/build/tabs.html:23 company/models.py:366
#: company/templates/company/tabs.html:33 order/templates/order/po_tabs.html:18
#: order/templates/order/purchase_order_detail.html:213
#: order/templates/order/so_tabs.html:23 part/models.py:838
-#: part/templates/part/tabs.html:73 stock/forms.py:315 stock/forms.py:347
-#: stock/forms.py:375 stock/models.py:484 stock/models.py:1554
-#: stock/templates/stock/tabs.html:26 templates/js/barcode.js:37
-#: templates/js/bom.js:293 templates/js/stock.js:128 templates/js/stock.js:624
+#: part/templates/part/tabs.html:73
+#: report/templates/report/inventree_build_order_base.html:175
+#: stock/forms.py:315 stock/forms.py:347 stock/forms.py:375 stock/models.py:487
+#: stock/models.py:1582 stock/templates/stock/tabs.html:26
+#: templates/js/barcode.js:37 templates/js/bom.js:293 templates/js/stock.js:128
+#: templates/js/stock.js:624
msgid "Notes"
msgstr "Notizen"
-#: build/models.py:225
+#: build/models.py:245
msgid "Extra build notes"
msgstr "Notizen für den Bau"
-#: build/models.py:607
+#: build/models.py:627
#, fuzzy
#| msgid "No action specified"
msgid "No build output specified"
msgstr "Keine Aktion angegeben"
-#: build/models.py:610
+#: build/models.py:630
msgid "Build output is already completed"
msgstr ""
-#: build/models.py:613
+#: build/models.py:633
#, fuzzy
#| msgid "Quantity does not match serial numbers"
msgid "Build output does not match Build Order"
msgstr "Anzahl stimmt nicht mit den Seriennummern überein"
-#: build/models.py:688
+#: build/models.py:708
#, fuzzy
#| msgid "Complete Build"
msgid "Completed build output"
msgstr "Bau fertigstellen"
-#: build/models.py:930
+#: build/models.py:950
msgid "BuildItem must be unique for build, stock_item and install_into"
msgstr ""
-#: build/models.py:952
+#: build/models.py:972
#, fuzzy
#| msgid "Allocate Stock to Build"
msgid "Build item must specify a build output"
msgstr "Lagerbestand dem Bau zuweisen"
-#: build/models.py:957
+#: build/models.py:977
#, python-brace-format
msgid "Selected stock item not found in BOM for part '{p}'"
msgstr "Ausgewähltes Lagerobjekt nicht in BOM für Teil '{p}' gefunden"
-#: build/models.py:961
+#: build/models.py:981
#, python-brace-format
msgid "Allocated quantity ({n}) must not exceed available quantity ({q})"
msgstr ""
"zugewiesene Anzahl ({n}) darf nicht die verfügbare ({q}) Anzahl überschreiten"
-#: build/models.py:968 order/models.py:736
+#: build/models.py:988 order/models.py:736
msgid "StockItem is over-allocated"
msgstr "Zu viele Lagerobjekte zugewiesen"
-#: build/models.py:972 order/models.py:739
+#: build/models.py:992 order/models.py:739
msgid "Allocation quantity must be greater than zero"
msgstr "Anzahl muss größer null sein"
-#: build/models.py:976
+#: build/models.py:996
msgid "Quantity must be 1 for serialized stock"
msgstr "Anzahl muss 1 für Objekte mit Seriennummer sein"
-#: build/models.py:1016
+#: build/models.py:1036
msgid "Build to allocate parts"
msgstr "Bau starten um Teile zuzuweisen"
-#: build/models.py:1023
+#: build/models.py:1043
#, fuzzy
#| msgid "Remove stock"
msgid "Source stock item"
msgstr "Bestand entfernen"
-#: build/models.py:1035
+#: build/models.py:1055
msgid "Stock quantity to allocate to build"
msgstr "Lagerobjekt-Anzahl dem Bau zuweisen"
-#: build/models.py:1043
+#: build/models.py:1063
#, fuzzy
#| msgid "Destination stock location"
msgid "Destination stock item"
@@ -722,7 +743,7 @@ msgstr "Teile bestellen"
msgid "Unallocate stock"
msgstr "Zuweisung aufheben"
-#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:778
+#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:781
msgid "Unallocate Stock"
msgstr "Zuweisung aufheben"
@@ -760,7 +781,7 @@ msgid ""
msgstr "Lagerobjekt dem Bau zuweisen"
#: build/templates/build/auto_allocate.html:18 stock/forms.py:345
-#: stock/templates/stock/item_base.html:268
+#: stock/templates/stock/item_base.html:264
#: stock/templates/stock/stock_adjust.html:17
#: templates/InvenTree/search.html:183 templates/js/barcode.js:363
#: templates/js/barcode.js:531 templates/js/build.js:434
@@ -805,7 +826,7 @@ msgid "Admin view"
msgstr "Admin"
#: build/templates/build/build_base.html:43
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
#: order/templates/order/order_base.html:32
#: order/templates/order/order_base.html:83
#: order/templates/order/sales_order_base.html:41
@@ -815,68 +836,101 @@ msgstr "Admin"
msgid "Overdue"
msgstr ""
-#: build/templates/build/build_base.html:51
+#: build/templates/build/build_base.html:52
+#, fuzzy
+#| msgid "Source Location"
+msgid "Print actions"
+msgstr "Quell-Standort"
+
+#: build/templates/build/build_base.html:56
+#, fuzzy
+#| msgid "Build Order"
+msgid "Print Build Order"
+msgstr "Bauauftrag"
+
+#: build/templates/build/build_base.html:62
+#, fuzzy
+#| msgid "Build parts"
+msgid "Build actions"
+msgstr "Bauteile"
+
+#: build/templates/build/build_base.html:66
#, fuzzy
#| msgid "Edited build"
msgid "Edit Build"
msgstr "Bau bearbeitet"
-#: build/templates/build/build_base.html:55
+#: build/templates/build/build_base.html:68
msgid "Complete Build"
msgstr "Bau fertigstellen"
-#: build/templates/build/build_base.html:58 build/views.py:58
+#: build/templates/build/build_base.html:69 build/views.py:58
msgid "Cancel Build"
msgstr "Bau abbrechen"
-#: build/templates/build/build_base.html:64
-msgid "Delete Build"
-msgstr "Bau entfernt"
-
-#: build/templates/build/build_base.html:74 build/templates/build/detail.html:9
+#: build/templates/build/build_base.html:82 build/templates/build/detail.html:9
msgid "Build Details"
msgstr "Bau-Status"
-#: build/templates/build/build_base.html:88
+#: build/templates/build/build_base.html:96
#: build/templates/build/detail.html:57
#: order/templates/order/receive_parts.html:24
-#: stock/templates/stock/item_base.html:367 templates/InvenTree/search.html:175
-#: templates/js/barcode.js:119 templates/js/build.js:697
+#: stock/templates/stock/item_base.html:363 templates/InvenTree/search.html:175
+#: templates/js/barcode.js:119 templates/js/build.js:703
#: templates/js/order.js:185 templates/js/order.js:279
#: templates/js/stock.js:585 templates/js/stock.js:1157
msgid "Status"
msgstr "Status"
-#: build/templates/build/build_base.html:96
-#: build/templates/build/detail.html:100
+#: build/templates/build/build_base.html:104
+#: build/templates/build/detail.html:119
#: order/templates/order/order_base.html:121
-#: order/templates/order/sales_order_base.html:114 templates/js/build.js:710
-#: templates/js/order.js:198 templates/js/order.js:292
+#: order/templates/order/sales_order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:128
+#: templates/js/build.js:716 templates/js/order.js:198
+#: templates/js/order.js:292
#, fuzzy
#| msgid "Shipment Date"
msgid "Target Date"
msgstr "Versanddatum"
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
msgid "This build was due on"
msgstr ""
-#: build/templates/build/build_base.html:107
+#: build/templates/build/build_base.html:115
#: build/templates/build/detail.html:62
msgid "Progress"
msgstr ""
-#: build/templates/build/build_base.html:120
+#: build/templates/build/build_base.html:128
#: build/templates/build/detail.html:82 order/models.py:650
#: order/templates/order/sales_order_base.html:9
#: order/templates/order/sales_order_base.html:33
#: order/templates/order/sales_order_notes.html:10
#: order/templates/order/sales_order_ship.html:25
#: part/templates/part/allocation.html:27
-#: stock/templates/stock/item_base.html:262 templates/js/order.js:240
+#: report/templates/report/inventree_build_order_base.html:138
+#: stock/templates/stock/item_base.html:258 templates/js/order.js:240
msgid "Sales Order"
msgstr "Bestellung"
+#: build/templates/build/build_base.html:135
+#: build/templates/build/detail.html:96
+#: report/templates/report/inventree_build_order_base.html:155
+#, fuzzy
+#| msgid "Issued"
+msgid "Issued By"
+msgstr "Aufgegeben"
+
+#: build/templates/build/build_base.html:142
+#: build/templates/build/detail.html:103
+#: report/templates/report/inventree_build_order_base.html:161
+#, fuzzy
+#| msgid "Responsible User"
+msgid "Responsible"
+msgstr "Verantwortlicher Benutzer"
+
#: build/templates/build/build_output.html:9 build/templates/build/tabs.html:17
msgid "Build Outputs"
msgstr "Bau-Ausgabe"
@@ -1007,30 +1061,30 @@ msgid "Destination location not specified"
msgstr "Hat dieses Teil Tracking für einzelne Objekte?"
#: build/templates/build/detail.html:68
-#: stock/templates/stock/item_base.html:286 templates/js/stock.js:593
+#: stock/templates/stock/item_base.html:282 templates/js/stock.js:593
#: templates/js/stock.js:1164 templates/js/table_filters.js:80
#: templates/js/table_filters.js:161
msgid "Batch"
msgstr "Los"
-#: build/templates/build/detail.html:95
+#: build/templates/build/detail.html:114
#: order/templates/order/order_base.html:108
-#: order/templates/order/sales_order_base.html:108 templates/js/build.js:705
+#: order/templates/order/sales_order_base.html:108 templates/js/build.js:711
msgid "Created"
msgstr "Erstellt"
-#: build/templates/build/detail.html:106
+#: build/templates/build/detail.html:125
#, fuzzy
#| msgid "No destination set"
msgid "No target date set"
msgstr "Kein Ziel gesetzt"
-#: build/templates/build/detail.html:111 templates/js/build.js:683
-#: templates/js/build.js:715
+#: build/templates/build/detail.html:130 templates/js/build.js:689
+#: templates/js/build.js:721
msgid "Completed"
msgstr "Fertig"
-#: build/templates/build/detail.html:115
+#: build/templates/build/detail.html:134
#, fuzzy
#| msgid "Build order allocation is complete"
msgid "Build not complete"
@@ -1042,17 +1096,23 @@ msgstr "Bau-Zuweisung ist vollständig"
msgid "Alter the quantity of stock allocated to the build output"
msgstr "Lagerobjekt-Anzahl dem Bau zuweisen"
-#: build/templates/build/index.html:27 build/views.py:658
+#: build/templates/build/index.html:28 build/views.py:658
msgid "New Build Order"
msgstr "Neuer Bauauftrag"
-#: build/templates/build/index.html:30
+#: build/templates/build/index.html:37 build/templates/build/index.html:38
+#, fuzzy
+#| msgid "Build Orders"
+msgid "Print Build Orders"
+msgstr "Bauaufträge"
+
+#: build/templates/build/index.html:43
#: order/templates/order/purchase_orders.html:22
#: order/templates/order/sales_orders.html:22
msgid "Display calendar view"
msgstr ""
-#: build/templates/build/index.html:33
+#: build/templates/build/index.html:46
#: order/templates/order/purchase_orders.html:25
#: order/templates/order/sales_orders.html:25
msgid "Display list view"
@@ -1124,7 +1184,7 @@ msgstr "Lagerbestand dem Bau zuweisen"
msgid "Create Build Output"
msgstr "Bau-Ausgabe"
-#: build/views.py:207 stock/models.py:897 stock/views.py:1804
+#: build/views.py:207 stock/models.py:900 stock/views.py:1804
#, fuzzy
#| msgid "Serial numbers already exist: "
msgid "Serial numbers already exist"
@@ -1204,91 +1264,91 @@ msgstr "Baufertigstellung bestätigen"
msgid "Build output completed"
msgstr "Bau-Zuweisung ist vollständig"
-#: build/views.py:703
+#: build/views.py:706
msgid "Created new build"
msgstr "Neuen Bau angelegt"
-#: build/views.py:724
+#: build/views.py:727
#, fuzzy
#| msgid "Edit Build Details"
msgid "Edit Build Order Details"
msgstr "Baudetails bearbeiten"
-#: build/views.py:758
+#: build/views.py:761
msgid "Edited build"
msgstr "Bau bearbeitet"
-#: build/views.py:767
+#: build/views.py:770
#, fuzzy
#| msgid "Complete Build"
msgid "Delete Build Order"
msgstr "Bau fertigstellen"
-#: build/views.py:784
+#: build/views.py:787
msgid "Removed parts from build allocation"
msgstr "Teile von Bauzuordnung entfernt"
-#: build/views.py:796
+#: build/views.py:799
#, fuzzy
#| msgid "Allocate Stock to Build"
msgid "Allocate stock to build output"
msgstr "Lagerbestand dem Bau zuweisen"
-#: build/views.py:840
+#: build/views.py:843
#, fuzzy
#| msgid "This stock item is allocated to Build"
msgid "Item must be currently in stock"
msgstr "Dieses Lagerobjekt ist dem Bau zugewiesen"
-#: build/views.py:846
+#: build/views.py:849
#, fuzzy
#| msgid "StockItem is over-allocated"
msgid "Stock item is over-allocated"
msgstr "Zu viele Lagerobjekte zugewiesen"
-#: build/views.py:847 templates/js/bom.js:220 templates/js/build.js:519
-#: templates/js/build.js:758
+#: build/views.py:850 templates/js/bom.js:220 templates/js/build.js:519
+#: templates/js/build.js:771
msgid "Available"
msgstr "verfügbar"
-#: build/views.py:849
+#: build/views.py:852
#, fuzzy
#| msgid "StockItem has been allocated"
msgid "Stock item must be selected"
msgstr "Lagerobjekt wurde zugewiesen"
-#: build/views.py:1012
+#: build/views.py:1015
msgid "Edit Stock Allocation"
msgstr "Teilzuordnung bearbeiten"
-#: build/views.py:1017
+#: build/views.py:1020
msgid "Updated Build Item"
msgstr "Bauobjekt aktualisiert"
-#: build/views.py:1046
+#: build/views.py:1049
#, fuzzy
#| msgid "Add Sales Order Attachment"
msgid "Add Build Order Attachment"
msgstr "Auftragsanhang hinzufügen"
-#: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170
+#: build/views.py:1063 order/views.py:113 order/views.py:166 part/views.py:170
#: stock/views.py:280
msgid "Added attachment"
msgstr "Anhang hinzugefügt"
-#: build/views.py:1096 order/views.py:193 order/views.py:215
+#: build/views.py:1099 order/views.py:193 order/views.py:215
msgid "Edit Attachment"
msgstr "Anhang bearbeiten"
-#: build/views.py:1107 order/views.py:198 order/views.py:220
+#: build/views.py:1110 order/views.py:198 order/views.py:220
msgid "Attachment updated"
msgstr "Anhang aktualisiert"
-#: build/views.py:1117 order/views.py:235 order/views.py:250
+#: build/views.py:1120 order/views.py:235 order/views.py:250
msgid "Delete Attachment"
msgstr "Anhang löschen"
-#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:338
+#: build/views.py:1126 order/views.py:242 order/views.py:257 stock/views.py:338
msgid "Deleted attachment"
msgstr "Anhang gelöscht"
@@ -1315,306 +1375,344 @@ msgid "Internal company name"
msgstr "Firmenname"
#: common/models.py:68
+msgid "Base URL"
+msgstr ""
+
+#: common/models.py:69
+#, fuzzy
+#| msgid "Brief description of the build"
+msgid "Base URL for server instance"
+msgstr "Kurze Beschreibung des Baus"
+
+#: common/models.py:75
#, fuzzy
#| msgid "Delete Currency"
msgid "Default Currency"
msgstr "Währung entfernen"
-#: common/models.py:69
+#: common/models.py:76
#, fuzzy
#| msgid "Delete Currency"
msgid "Default currency"
msgstr "Währung entfernen"
-#: common/models.py:75
+#: common/models.py:82
#, fuzzy
#| msgid "Source Location"
msgid "Barcode Support"
msgstr "Quell-Standort"
-#: common/models.py:76
+#: common/models.py:83
msgid "Enable barcode scanner support"
msgstr ""
-#: common/models.py:82
+#: common/models.py:89
msgid "IPN Regex"
msgstr ""
-#: common/models.py:83
+#: common/models.py:90
msgid "Regular expression pattern for matching Part IPN"
msgstr ""
-#: common/models.py:87
+#: common/models.py:94
#, fuzzy
#| msgid "Duplicate Part"
msgid "Allow Duplicate IPN"
msgstr "Teil duplizieren"
-#: common/models.py:88
+#: common/models.py:95
msgid "Allow multiple parts to share the same IPN"
msgstr ""
-#: common/models.py:94
+#: common/models.py:101
#, fuzzy
#| msgid "Import BOM data"
msgid "Copy Part BOM Data"
msgstr "Stückliste importieren"
-#: common/models.py:95
-msgid "Copy BOM data by default when duplicating a part"
-msgstr ""
-
-#: common/models.py:101
-#, fuzzy
-#| msgid "Parameters"
-msgid "Copy Part Parameter Data"
-msgstr "Parameter"
-
#: common/models.py:102
-msgid "Copy parameter data by default when duplicating a part"
+msgid "Copy BOM data by default when duplicating a part"
msgstr ""
#: common/models.py:108
#, fuzzy
#| msgid "Parameters"
-msgid "Copy Part Test Data"
+msgid "Copy Part Parameter Data"
msgstr "Parameter"
#: common/models.py:109
-msgid "Copy test data by default when duplicating a part"
+msgid "Copy parameter data by default when duplicating a part"
msgstr ""
#: common/models.py:115
#, fuzzy
+#| msgid "Parameters"
+msgid "Copy Part Test Data"
+msgstr "Parameter"
+
+#: common/models.py:116
+msgid "Copy test data by default when duplicating a part"
+msgstr ""
+
+#: common/models.py:122
+#, fuzzy
#| msgid "Edit Part Parameter Template"
msgid "Copy Category Parameter Templates"
msgstr "Teilparametervorlage bearbeiten"
-#: common/models.py:116
+#: common/models.py:123
msgid "Copy category parameter templates when creating a part"
msgstr ""
-#: common/models.py:122 part/templates/part/detail.html:155
-#: report/models.py:159 stock/forms.py:257 templates/js/table_filters.js:23
+#: common/models.py:129 part/templates/part/detail.html:157
+#: report/models.py:168 stock/forms.py:257 templates/js/table_filters.js:23
#: templates/js/table_filters.js:270
msgid "Template"
msgstr "Vorlage"
-#: common/models.py:123
+#: common/models.py:130
#, fuzzy
#| msgid "Part is not a virtual part"
msgid "Parts are templates by default"
msgstr "Teil ist nicht virtuell"
-#: common/models.py:129 part/models.py:801 part/templates/part/detail.html:165
+#: common/models.py:136 part/models.py:801 part/templates/part/detail.html:167
#: templates/js/table_filters.js:282
msgid "Assembly"
msgstr "Baugruppe"
-#: common/models.py:130
+#: common/models.py:137
#, fuzzy
#| msgid "Part can be assembled from other parts"
msgid "Parts can be assembled from other components by default"
msgstr "Teil kann aus anderen Teilen angefertigt werden"
-#: common/models.py:136 part/models.py:807 part/templates/part/detail.html:175
+#: common/models.py:143 part/models.py:807 part/templates/part/detail.html:177
#: templates/js/table_filters.js:286
msgid "Component"
msgstr "Komponente"
-#: common/models.py:137
+#: common/models.py:144
#, fuzzy
#| msgid "Part can be used in assemblies"
msgid "Parts can be used as sub-components by default"
msgstr "Teil kann in Baugruppen benutzt werden"
-#: common/models.py:143 part/models.py:818 part/templates/part/detail.html:195
+#: common/models.py:150 part/models.py:818 part/templates/part/detail.html:197
msgid "Purchaseable"
msgstr "Kaufbar"
-#: common/models.py:144
+#: common/models.py:151
msgid "Parts are purchaseable by default"
msgstr ""
-#: common/models.py:150 part/models.py:823 part/templates/part/detail.html:205
+#: common/models.py:157 part/models.py:823 part/templates/part/detail.html:207
#: templates/js/table_filters.js:294
msgid "Salable"
msgstr "Verkäuflich"
-#: common/models.py:151
+#: common/models.py:158
msgid "Parts are salable by default"
msgstr ""
-#: common/models.py:157 part/models.py:813 part/templates/part/detail.html:185
+#: common/models.py:164 part/models.py:813 part/templates/part/detail.html:187
#: templates/js/table_filters.js:31 templates/js/table_filters.js:298
msgid "Trackable"
msgstr "nachverfolgbar"
-#: common/models.py:158
+#: common/models.py:165
msgid "Parts are trackable by default"
msgstr ""
-#: common/models.py:164 part/models.py:833 part/templates/part/detail.html:145
+#: common/models.py:171 part/models.py:833 part/templates/part/detail.html:147
#: templates/js/table_filters.js:27
msgid "Virtual"
msgstr "Virtuell"
-#: common/models.py:165
+#: common/models.py:172
#, fuzzy
#| msgid "Part is not a virtual part"
msgid "Parts are virtual by default"
msgstr "Teil ist nicht virtuell"
-#: common/models.py:171
+#: common/models.py:178
#, fuzzy
#| msgid "Stock Quantity"
msgid "Show Quantity in Forms"
msgstr "Bestand"
-#: common/models.py:172
+#: common/models.py:179
msgid "Display available part quantity in some forms"
msgstr ""
-#: common/models.py:178
+#: common/models.py:185
+msgid "Debug Mode"
+msgstr ""
+
+#: common/models.py:186
+msgid "Generate reports in debug mode (HTML output)"
+msgstr ""
+
+#: common/models.py:192
+msgid "Page Size"
+msgstr ""
+
+#: common/models.py:193
+msgid "Default page size for PDF reports"
+msgstr ""
+
+#: common/models.py:203
+#, fuzzy
+#| msgid "Edit notes"
+msgid "Test Reports"
+msgstr "Bermerkungen bearbeiten"
+
+#: common/models.py:204
+#, fuzzy
+#| msgid "Parameter Template"
+msgid "Enable generation of test reports"
+msgstr "Parameter Vorlage"
+
+#: common/models.py:210
#, fuzzy
#| msgid "Stock Export Options"
msgid "Stock Expiry"
msgstr "Lagerbestandsexportoptionen"
-#: common/models.py:179
+#: common/models.py:211
msgid "Enable stock expiry functionality"
msgstr ""
-#: common/models.py:185
+#: common/models.py:217
#, fuzzy
#| msgid "Serialize Stock"
msgid "Sell Expired Stock"
msgstr "Lagerbestand erfassen"
-#: common/models.py:186
+#: common/models.py:218
msgid "Allow sale of expired stock"
msgstr ""
-#: common/models.py:192
+#: common/models.py:224
#, fuzzy
#| msgid "Stock Item"
msgid "Stock Stale Time"
msgstr "Lagerobjekt"
-#: common/models.py:193
+#: common/models.py:225
msgid "Number of days stock items are considered stale before expiring"
msgstr ""
-#: common/models.py:195 part/templates/part/detail.html:116
+#: common/models.py:227 part/templates/part/detail.html:118
msgid "days"
msgstr ""
-#: common/models.py:200
+#: common/models.py:232
#, fuzzy
#| msgid "Builds"
msgid "Build Expired Stock"
msgstr "Baue"
-#: common/models.py:201
+#: common/models.py:233
msgid "Allow building with expired stock"
msgstr ""
-#: common/models.py:207
+#: common/models.py:239
msgid "Stock Ownership Control"
msgstr ""
-#: common/models.py:208
+#: common/models.py:240
msgid "Enable ownership control over stock locations and items"
msgstr ""
-#: common/models.py:214
+#: common/models.py:246
#, fuzzy
#| msgid "Order Reference"
msgid "Build Order Reference Prefix"
msgstr "Bestellreferenz"
-#: common/models.py:215
+#: common/models.py:247
#, fuzzy
#| msgid "Order reference"
msgid "Prefix value for build order reference"
msgstr "Bestell-Referenz"
-#: common/models.py:220
+#: common/models.py:252
#, fuzzy
#| msgid "Order Reference"
msgid "Build Order Reference Regex"
msgstr "Bestellreferenz"
-#: common/models.py:221
+#: common/models.py:253
msgid "Regular expression pattern for matching build order reference"
msgstr ""
-#: common/models.py:225
+#: common/models.py:257
#, fuzzy
#| msgid "Sales Order Reference"
msgid "Sales Order Reference Prefix"
msgstr "Bestellungsreferenz"
-#: common/models.py:226
+#: common/models.py:258
#, fuzzy
#| msgid "Order reference"
msgid "Prefix value for sales order reference"
msgstr "Bestell-Referenz"
-#: common/models.py:231
+#: common/models.py:263
#, fuzzy
#| msgid "Order reference"
msgid "Purchase Order Reference Prefix"
msgstr "Bestell-Referenz"
-#: common/models.py:232
+#: common/models.py:264
#, fuzzy
#| msgid "Order reference"
msgid "Prefix value for purchase order reference"
msgstr "Bestell-Referenz"
-#: common/models.py:455
+#: common/models.py:487
msgid "Settings key (must be unique - case insensitive"
msgstr ""
"Einstellungs-Schlüssel (muss einzigartig sein, Groß-/ Kleinschreibung wird "
"nicht beachtet)"
-#: common/models.py:457
+#: common/models.py:489
msgid "Settings value"
msgstr "Einstellungs-Wert"
-#: common/models.py:514
+#: common/models.py:551
msgid "Value must be a boolean value"
msgstr ""
-#: common/models.py:524
+#: common/models.py:561
#, fuzzy
#| msgid "Must enter integer value"
msgid "Value must be an integer value"
msgstr "Nur Ganzzahl eingeben"
-#: common/models.py:538
+#: common/models.py:575
msgid "Key string must be unique"
msgstr "Schlüsseltext muss eindeutig sein"
-#: common/models.py:611 company/forms.py:113
+#: common/models.py:648 company/forms.py:113
#, fuzzy
#| msgid "Price Breaks"
msgid "Price break quantity"
msgstr "Preisstaffelung"
-#: common/models.py:619 company/templates/company/supplier_part_pricing.html:80
+#: common/models.py:656 company/templates/company/supplier_part_pricing.html:80
#: part/templates/part/sale_prices.html:87 templates/js/bom.js:245
msgid "Price"
msgstr "Preis"
-#: common/models.py:620
+#: common/models.py:657
#, fuzzy
#| msgid "Enter a valid quantity"
msgid "Unit price at specified quantity"
msgstr "Bitte eine gültige Anzahl eingeben"
-#: common/models.py:643
+#: common/models.py:680
#, fuzzy
#| msgid "Default Location"
msgid "Default"
@@ -1735,8 +1833,8 @@ msgstr "Produziert diese Firma Teile?"
msgid "Currency"
msgstr "Währung bearbeiten"
-#: company/models.py:313 stock/models.py:366
-#: stock/templates/stock/item_base.html:218
+#: company/models.py:313 stock/models.py:369
+#: stock/templates/stock/item_base.html:214
msgid "Base Part"
msgstr "Basisteil"
@@ -1749,7 +1847,7 @@ msgstr "Teil auswählen"
#: company/templates/company/supplier_part_detail.html:21
#: order/templates/order/order_base.html:89
#: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170
-#: stock/templates/stock/item_base.html:328 templates/js/company.js:48
+#: stock/templates/stock/item_base.html:324 templates/js/company.js:48
#: templates/js/company.js:164 templates/js/order.js:167
msgid "Supplier"
msgstr "Zulieferer"
@@ -1788,8 +1886,9 @@ msgstr "MPN"
msgid "Manufacturer part number"
msgstr "Hersteller-Teilenummer"
-#: company/models.py:353 part/models.py:711 templates/js/company.js:208
-#: templates/js/part.js:451
+#: company/models.py:353 part/models.py:711
+#: report/templates/report/inventree_build_order_base.html:167
+#: templates/js/company.js:208 templates/js/part.js:451
msgid "Link"
msgstr "Link"
@@ -1854,8 +1953,8 @@ msgid "Uses default currency"
msgstr "Währung entfernen"
#: company/templates/company/detail.html:62
-#: order/templates/order/sales_order_base.html:89 stock/models.py:401
-#: stock/models.py:402 stock/templates/stock/item_base.html:245
+#: order/templates/order/sales_order_base.html:89 stock/models.py:404
+#: stock/models.py:405 stock/templates/stock/item_base.html:241
#: templates/js/company.js:40 templates/js/order.js:261
msgid "Customer"
msgstr "Kunde"
@@ -1898,7 +1997,7 @@ msgid "Delete Parts"
msgstr "Teile löschen"
#: company/templates/company/detail_part.html:63
-#: part/templates/part/bom.html:182 part/templates/part/category.html:116
+#: part/templates/part/bom.html:185 part/templates/part/category.html:116
#: templates/js/stock.js:1035
msgid "New Part"
msgstr "Neues Teil"
@@ -1931,8 +2030,8 @@ msgstr "Zuliefererbestand"
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
-#: part/templates/part/bom.html:63 part/templates/part/category.html:112
-#: part/templates/part/category.html:126 part/templates/part/stock.html:51
+#: part/templates/part/category.html:112 part/templates/part/category.html:126
+#: part/templates/part/stock.html:51
msgid "Export"
msgstr "Exportieren"
@@ -1955,7 +2054,7 @@ msgstr ""
#: order/templates/order/purchase_orders.html:8
#: order/templates/order/purchase_orders.html:13
#: part/templates/part/orders.html:9 part/templates/part/tabs.html:48
-#: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33
+#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:37
#: users/models.py:37
msgid "Purchase Orders"
msgstr "Bestellungen"
@@ -1975,7 +2074,7 @@ msgstr "Neue Bestellung"
#: order/templates/order/sales_orders.html:8
#: order/templates/order/sales_orders.html:13
#: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56
-#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42
+#: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:46
#: users/models.py:38
msgid "Sales Orders"
msgstr "Bestellungen"
@@ -1991,13 +2090,13 @@ msgid "New Sales Order"
msgstr "Neuer Auftrag"
#: company/templates/company/supplier_part_base.html:6
-#: company/templates/company/supplier_part_base.html:19 stock/models.py:375
-#: stock/templates/stock/item_base.html:333 templates/js/company.js:180
+#: company/templates/company/supplier_part_base.html:19 stock/models.py:378
+#: stock/templates/stock/item_base.html:329 templates/js/company.js:180
msgid "Supplier Part"
msgstr "Zulieferer-Teil"
#: company/templates/company/supplier_part_base.html:26
-#: part/templates/part/orders.html:14 part/templates/part/part_base.html:69
+#: part/templates/part/orders.html:14 part/templates/part/part_base.html:68
msgid "Order part"
msgstr "Teil bestellen"
@@ -2069,8 +2168,8 @@ msgstr "Bepreisung"
#: company/templates/company/supplier_part_tabs.html:8
#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18
#: stock/templates/stock/location.html:29 templates/InvenTree/search.html:155
-#: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192
-#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:22
+#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:192
+#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:26
msgid "Stock"
msgstr "Lagerbestand"
@@ -2082,21 +2181,21 @@ msgstr "Bestellungen"
#: order/templates/order/receive_parts.html:14 part/models.py:321
#: part/templates/part/cat_link.html:7 part/templates/part/category.html:94
#: part/templates/part/category_tabs.html:6
-#: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19
+#: templates/InvenTree/settings/tabs.html:25 templates/navbar.html:23
#: templates/stats.html:35 templates/stats.html:44 users/models.py:33
msgid "Parts"
msgstr "Teile"
#: company/views.py:55 part/templates/part/tabs.html:42
-#: templates/navbar.html:31
+#: templates/navbar.html:35
msgid "Suppliers"
msgstr "Zulieferer"
-#: company/views.py:62 templates/navbar.html:32
+#: company/views.py:62 templates/navbar.html:36
msgid "Manufacturers"
msgstr "Hersteller"
-#: company/views.py:69 templates/navbar.html:41
+#: company/views.py:69 templates/navbar.html:45
msgid "Customers"
msgstr "Kunden"
@@ -2174,53 +2273,53 @@ msgstr "Preisstaffel bearbeiten"
msgid "Delete Price Break"
msgstr "Preisstaffel löschen"
-#: label/api.py:171 report/api.py:161
+#: label/api.py:179
#, fuzzy
#| msgid "Move Stock Items"
msgid "Must provide valid StockItem(s)"
msgstr "Lagerobjekte bewegen"
-#: label/api.py:185 label/api.py:337
+#: label/api.py:193 label/api.py:353
msgid "Error during label rendering"
msgstr ""
-#: label/api.py:324
+#: label/api.py:340
msgid "Must provide valid StockLocation(s)"
msgstr ""
-#: label/models.py:69
+#: label/models.py:70
#, fuzzy
#| msgid "Part name"
msgid "Label name"
msgstr "Name des Teils"
-#: label/models.py:76
+#: label/models.py:77
#, fuzzy
#| msgid "Part description"
msgid "Label description"
msgstr "Beschreibung des Teils"
-#: label/models.py:83 stock/forms.py:200
+#: label/models.py:84 stock/forms.py:200
msgid "Label"
msgstr ""
-#: label/models.py:84
+#: label/models.py:85
msgid "Label template file"
msgstr ""
-#: label/models.py:90 report/models.py:172
+#: label/models.py:91 report/models.py:257
msgid "Enabled"
msgstr ""
-#: label/models.py:91
+#: label/models.py:92
msgid "Label template is enabled"
msgstr ""
-#: label/models.py:137 label/models.py:190
+#: label/models.py:138 label/models.py:194
msgid "Query filters (comma-separated list of key=value pairs"
msgstr ""
-#: label/models.py:138 label/models.py:191 report/models.py:194
+#: label/models.py:139 label/models.py:195 report/models.py:277
msgid "Filters"
msgstr ""
@@ -2330,7 +2429,7 @@ msgid "Date order was completed"
msgstr "Bestellung als vollständig markieren"
#: order/models.py:230 order/models.py:329 part/views.py:1506
-#: stock/models.py:265 stock/models.py:881
+#: stock/models.py:268 stock/models.py:884
msgid "Quantity must be greater than zero"
msgstr "Anzahl muss größer Null sein"
@@ -2342,6 +2441,12 @@ msgstr "Teile-Zulieferer muss dem Zulieferer des Kaufvertrags entsprechen"
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr "Nur Teile aufgegebener Bestllungen können empfangen werden"
+#: order/models.py:346
+#, fuzzy
+#| msgid "Receive line item"
+msgid "Received items"
+msgstr "Position empfangen"
+
#: order/models.py:427
msgid "Company to which the items are being sold"
msgstr ""
@@ -2368,7 +2473,7 @@ msgstr "Position - Notizen"
#: order/models.py:608 order/templates/order/order_base.html:9
#: order/templates/order/order_base.html:24
-#: stock/templates/stock/item_base.html:300 templates/js/order.js:145
+#: stock/templates/stock/item_base.html:296 templates/js/order.js:145
msgid "Purchase Order"
msgstr "Kaufvertrag"
@@ -2380,8 +2485,8 @@ msgstr "Zulieferer-Teil"
msgid "Number of items received"
msgstr "Empfangene Objekt-Anzahl"
-#: order/models.py:631 stock/models.py:494
-#: stock/templates/stock/item_base.html:307
+#: order/models.py:631 stock/models.py:497
+#: stock/templates/stock/item_base.html:303
#, fuzzy
#| msgid "Purchase Order"
msgid "Purchase Price"
@@ -2458,6 +2563,7 @@ msgid "Supplier Reference"
msgstr "Zuliefererreferenz"
#: order/templates/order/order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:124
msgid "Issued"
msgstr "Aufgegeben"
@@ -2603,7 +2709,7 @@ msgid "Select parts to receive against this order"
msgstr ""
#: order/templates/order/receive_parts.html:21
-#: part/templates/part/part_base.html:148 templates/js/part.js:434
+#: part/templates/part/part_base.html:147 templates/js/part.js:434
msgid "On Order"
msgstr "bestellt"
@@ -2645,24 +2751,26 @@ msgid "Sales Order Items"
msgstr "Auftragspositionen"
#: order/templates/order/sales_order_detail.html:72
-#: order/templates/order/sales_order_detail.html:154 stock/models.py:406
-#: stock/templates/stock/item_base.html:232 templates/js/build.js:418
+#: order/templates/order/sales_order_detail.html:154
+#: report/templates/report/inventree_test_report_base.html:75
+#: stock/models.py:409 stock/templates/stock/item_base.html:228
+#: templates/js/build.js:418
msgid "Serial Number"
msgstr "Seriennummer"
#: order/templates/order/sales_order_detail.html:96 templates/js/build.js:459
-#: templates/js/build.js:769
+#: templates/js/build.js:782
msgid "Edit stock allocation"
msgstr "Lagerobjekt-Standort bearbeiten"
#: order/templates/order/sales_order_detail.html:97 templates/js/build.js:461
-#: templates/js/build.js:770
+#: templates/js/build.js:783
msgid "Delete stock allocation"
msgstr "Zuweisung löschen"
#: order/templates/order/sales_order_detail.html:225
#: part/templates/part/tabs.html:23 templates/js/build.js:523
-#: templates/js/build.js:765
+#: templates/js/build.js:778
msgid "Allocated"
msgstr "Zugeordnet"
@@ -2873,7 +2981,7 @@ msgstr "Zuordnung entfernen"
msgid "Default Location"
msgstr "Standard-Lagerort"
-#: part/bom.py:139 part/templates/part/part_base.html:121
+#: part/bom.py:139 part/templates/part/part_base.html:120
msgid "Available Stock"
msgstr "Verfügbarer Lagerbestand"
@@ -3133,7 +3241,7 @@ msgid "Part category"
msgstr "Teile-Kategorie"
#: part/models.py:698 part/templates/part/detail.html:25
-#: part/templates/part/part_base.html:98 templates/js/part.js:180
+#: part/templates/part/part_base.html:97 templates/js/part.js:180
msgid "IPN"
msgstr "IPN (Interne Produktnummer)"
@@ -3145,7 +3253,7 @@ msgstr "Interne Teilenummer"
msgid "Part revision or version number"
msgstr "Revisions- oder Versionsnummer"
-#: part/models.py:706 part/templates/part/detail.html:32
+#: part/models.py:706 part/templates/part/detail.html:32 report/models.py:181
#: templates/js/part.js:184
msgid "Revision"
msgstr "Revision"
@@ -3172,7 +3280,7 @@ msgstr "Standard-Zulieferer"
msgid "Expiry time (in days) for stock items of this part"
msgstr ""
-#: part/models.py:788 part/templates/part/detail.html:108
+#: part/models.py:788 part/templates/part/detail.html:110
msgid "Minimum Stock"
msgstr "Minimaler Lagerbestand"
@@ -3180,7 +3288,7 @@ msgstr "Minimaler Lagerbestand"
msgid "Minimum allowed stock level"
msgstr "Minimal zulässiger Lagerbestand"
-#: part/models.py:795 part/templates/part/detail.html:102
+#: part/models.py:795 part/templates/part/detail.html:103
#: part/templates/part/params.html:26
msgid "Units"
msgstr "Einheiten"
@@ -3209,7 +3317,7 @@ msgstr "Kann dieses Teil von externen Zulieferern gekauft werden?"
msgid "Can this part be sold to customers?"
msgstr "Kann dieses Teil an Kunden verkauft werden?"
-#: part/models.py:828 part/templates/part/detail.html:222
+#: part/models.py:828 part/templates/part/detail.html:224
#: templates/js/table_filters.js:19 templates/js/table_filters.js:55
#: templates/js/table_filters.js:196 templates/js/table_filters.js:265
msgid "Active"
@@ -3362,7 +3470,7 @@ msgid "BOM line checksum"
msgstr "Prüfsumme der Stückliste"
#: part/models.py:1967 part/views.py:1512 part/views.py:1564
-#: stock/models.py:255
+#: stock/models.py:258
#, fuzzy
#| msgid "Overage must be an integer value or a percentage"
msgid "Quantity must be integer value for trackable parts"
@@ -3407,8 +3515,8 @@ msgstr "Bestellung"
#: part/templates/part/allocation.html:45
#: stock/templates/stock/item_base.html:8
#: stock/templates/stock/item_base.html:89
-#: stock/templates/stock/item_base.html:315
-#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751
+#: stock/templates/stock/item_base.html:311
+#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:764
#: templates/js/stock.js:880 templates/js/stock.js:1140
msgid "Stock Item"
msgstr "Lagerobjekt"
@@ -3439,76 +3547,49 @@ msgstr "Ausgewählte Stücklistenpositionen entfernen"
msgid "Import BOM data"
msgstr "Stückliste importieren"
-#: part/templates/part/bom.html:38
-msgid "Import from File"
-msgstr ""
-
#: part/templates/part/bom.html:41
msgid "Copy BOM from parent part"
msgstr ""
-#: part/templates/part/bom.html:42
-#, fuzzy
-#| msgid "Parameters"
-msgid "Copy from Parent"
-msgstr "Parameter"
-
#: part/templates/part/bom.html:45
msgid "New BOM Item"
msgstr "Neue Stücklistenposition"
-#: part/templates/part/bom.html:46
-#, fuzzy
-#| msgid "Add Line Item"
-msgid "Add Item"
-msgstr "Position hinzufügen"
-
#: part/templates/part/bom.html:48
msgid "Finish Editing"
msgstr "Bearbeitung beenden"
-#: part/templates/part/bom.html:49
-#, fuzzy
-#| msgid "Finish Editing"
-msgid "Finished"
-msgstr "Bearbeitung beenden"
-
#: part/templates/part/bom.html:53
msgid "Edit BOM"
msgstr "Stückliste bearbeiten"
-#: part/templates/part/bom.html:54 part/templates/part/params.html:38
-#: templates/InvenTree/settings/user.html:19
-msgid "Edit"
-msgstr "Bearbeiten"
-
#: part/templates/part/bom.html:57
msgid "Validate Bill of Materials"
msgstr "Stückliste validieren"
-#: part/templates/part/bom.html:58
-#, fuzzy
-#| msgid "Validate BOM"
-msgid "Validate"
-msgstr "BOM validieren"
-
-#: part/templates/part/bom.html:62 part/views.py:1803
+#: part/templates/part/bom.html:63 part/views.py:1803
msgid "Export Bill of Materials"
msgstr "Stückliste exportieren"
-#: part/templates/part/bom.html:123
+#: part/templates/part/bom.html:66
+#, fuzzy
+#| msgid "Parameter Template"
+msgid "Print BOM Report"
+msgstr "Parameter Vorlage"
+
+#: part/templates/part/bom.html:126
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "Delete selected BOM items?"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
-#: part/templates/part/bom.html:124
+#: part/templates/part/bom.html:127
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "All selected BOM items will be deleted"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
-#: part/templates/part/bom.html:183 part/views.py:594
+#: part/templates/part/bom.html:186 part/views.py:594
#: templates/js/stock.js:1036
msgid "Create New Part"
msgstr "Neues Teil anlegen"
@@ -3762,87 +3843,87 @@ msgstr "Seriennummer"
msgid "No serial numbers recorded"
msgstr "Keine Seriennummern gefunden"
-#: part/templates/part/detail.html:115
+#: part/templates/part/detail.html:117
#, fuzzy
#| msgid "Stock Export Options"
msgid "Stock Expiry Time"
msgstr "Lagerbestandsexportoptionen"
-#: part/templates/part/detail.html:121 templates/js/order.js:287
+#: part/templates/part/detail.html:123 templates/js/order.js:287
msgid "Creation Date"
msgstr "Erstelldatum"
-#: part/templates/part/detail.html:127
+#: part/templates/part/detail.html:129
msgid "Created By"
msgstr "Erstellt von"
-#: part/templates/part/detail.html:134
+#: part/templates/part/detail.html:136
msgid "Responsible User"
msgstr "Verantwortlicher Benutzer"
-#: part/templates/part/detail.html:148
+#: part/templates/part/detail.html:150
msgid "Part is virtual (not a physical part)"
msgstr "Teil ist virtuell (kein physisches Teil)"
-#: part/templates/part/detail.html:150
+#: part/templates/part/detail.html:152
msgid "Part is not a virtual part"
msgstr "Teil ist nicht virtuell"
-#: part/templates/part/detail.html:158
+#: part/templates/part/detail.html:160
#, fuzzy
#| msgid "Part cannot be a template part if it is a variant of another part"
msgid "Part is a template part (variants can be made from this part)"
msgstr "Teil kann keine Vorlage sein wenn es Variante eines anderen Teils ist"
-#: part/templates/part/detail.html:160
+#: part/templates/part/detail.html:162
#, fuzzy
#| msgid "Part is not a virtual part"
msgid "Part is not a template part"
msgstr "Teil ist nicht virtuell"
-#: part/templates/part/detail.html:168
+#: part/templates/part/detail.html:170
msgid "Part can be assembled from other parts"
msgstr "Teil kann aus anderen Teilen angefertigt werden"
-#: part/templates/part/detail.html:170
+#: part/templates/part/detail.html:172
msgid "Part cannot be assembled from other parts"
msgstr "Teil kann nicht aus anderen Teilen angefertigt werden"
-#: part/templates/part/detail.html:178
+#: part/templates/part/detail.html:180
msgid "Part can be used in assemblies"
msgstr "Teil kann in Baugruppen benutzt werden"
-#: part/templates/part/detail.html:180
+#: part/templates/part/detail.html:182
msgid "Part cannot be used in assemblies"
msgstr "Teil kann nicht in Baugruppen benutzt werden"
-#: part/templates/part/detail.html:188
+#: part/templates/part/detail.html:190
msgid "Part stock is tracked by serial number"
msgstr "Teilebestand in der Seriennummer hinterlegt"
-#: part/templates/part/detail.html:190
+#: part/templates/part/detail.html:192
msgid "Part stock is not tracked by serial number"
msgstr "Teilebestand ist nicht in der Seriennummer hinterlegt"
-#: part/templates/part/detail.html:198 part/templates/part/detail.html:200
+#: part/templates/part/detail.html:200 part/templates/part/detail.html:202
msgid "Part can be purchased from external suppliers"
msgstr "Teil kann von externen Zulieferern gekauft werden"
-#: part/templates/part/detail.html:208
+#: part/templates/part/detail.html:210
msgid "Part can be sold to customers"
msgstr "Teil kann an Kunden verkauft werden"
-#: part/templates/part/detail.html:210
+#: part/templates/part/detail.html:212
msgid "Part cannot be sold to customers"
msgstr "Teil kann nicht an Kunden verkauft werden"
-#: part/templates/part/detail.html:225
+#: part/templates/part/detail.html:227
#, fuzzy
#| msgid "This part is not active"
msgid "Part is active"
msgstr "Dieses Teil ist nicht aktiv"
-#: part/templates/part/detail.html:227
+#: part/templates/part/detail.html:229
#, fuzzy
#| msgid "This part is not active"
msgid "Part is not active"
@@ -3866,13 +3947,19 @@ msgstr "Parameter hinzufügen"
msgid "New Parameter"
msgstr "Neuer Parameter"
-#: part/templates/part/params.html:25 stock/models.py:1541
-#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:124
+#: part/templates/part/params.html:25
+#: report/templates/report/inventree_test_report_base.html:90
+#: stock/models.py:1569 templates/InvenTree/settings/header.html:8
+#: templates/js/stock.js:124
msgid "Value"
msgstr "Wert"
+#: part/templates/part/params.html:38 templates/InvenTree/settings/user.html:19
+msgid "Edit"
+msgstr "Bearbeiten"
+
#: part/templates/part/params.html:41 part/templates/part/related.html:41
-#: part/templates/part/supplier.html:19 users/models.py:164
+#: part/templates/part/supplier.html:19 users/models.py:167
msgid "Delete"
msgstr "Löschen"
@@ -3903,79 +3990,79 @@ msgstr "Inaktiv"
msgid "Star this part"
msgstr "Teil favorisieren"
-#: part/templates/part/part_base.html:51
+#: part/templates/part/part_base.html:50
#: stock/templates/stock/item_base.html:127
-#: stock/templates/stock/location.html:45
+#: stock/templates/stock/location.html:44
#, fuzzy
#| msgid "Source Location"
msgid "Barcode actions"
msgstr "Quell-Standort"
-#: part/templates/part/part_base.html:53
+#: part/templates/part/part_base.html:52
#: stock/templates/stock/item_base.html:129
-#: stock/templates/stock/location.html:47
+#: stock/templates/stock/location.html:46
#, fuzzy
#| msgid "Part QR Code"
msgid "Show QR Code"
msgstr "Teil-QR-Code"
-#: part/templates/part/part_base.html:54
-#: stock/templates/stock/item_base.html:147
-#: stock/templates/stock/location.html:48
+#: part/templates/part/part_base.html:53
+#: stock/templates/stock/item_base.html:145
+#: stock/templates/stock/location.html:47
msgid "Print Label"
msgstr ""
-#: part/templates/part/part_base.html:59
+#: part/templates/part/part_base.html:58
msgid "Show pricing information"
msgstr "Kosteninformationen ansehen"
-#: part/templates/part/part_base.html:63
+#: part/templates/part/part_base.html:62
#, fuzzy
#| msgid "Count stock"
msgid "Count part stock"
msgstr "Bestand zählen"
-#: part/templates/part/part_base.html:78
+#: part/templates/part/part_base.html:77
#, fuzzy
#| msgid "Source Location"
msgid "Part actions"
msgstr "Quell-Standort"
-#: part/templates/part/part_base.html:81
+#: part/templates/part/part_base.html:80
#, fuzzy
#| msgid "Duplicate Part"
msgid "Duplicate part"
msgstr "Teil duplizieren"
-#: part/templates/part/part_base.html:84
+#: part/templates/part/part_base.html:83
#, fuzzy
#| msgid "Edit Template"
msgid "Edit part"
msgstr "Vorlage bearbeiten"
-#: part/templates/part/part_base.html:87
+#: part/templates/part/part_base.html:86
#, fuzzy
#| msgid "Delete Parts"
msgid "Delete part"
msgstr "Teile löschen"
-#: part/templates/part/part_base.html:127 templates/js/table_filters.js:121
+#: part/templates/part/part_base.html:126 templates/js/table_filters.js:121
msgid "In Stock"
msgstr "Auf Lager"
-#: part/templates/part/part_base.html:134
+#: part/templates/part/part_base.html:133
msgid "Allocated to Build Orders"
msgstr "Zu Bauaufträgen zugeordnet"
-#: part/templates/part/part_base.html:141
+#: part/templates/part/part_base.html:140
msgid "Allocated to Sales Orders"
msgstr "Zu Aufträgen zugeordnet"
-#: part/templates/part/part_base.html:163 templates/js/bom.js:260
+#: part/templates/part/part_base.html:162 templates/js/bom.js:260
msgid "Can Build"
msgstr "Herstellbar?"
-#: part/templates/part/part_base.html:169
+#: part/templates/part/part_base.html:168
msgid "Underway"
msgstr "unterwegs"
@@ -4086,7 +4173,7 @@ msgstr "Stückliste"
msgid "Used In"
msgstr "Benutzt in"
-#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:373
+#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:369
msgid "Tests"
msgstr ""
@@ -4375,42 +4462,123 @@ msgstr "BOM-Position beaarbeiten"
msgid "Confim BOM item deletion"
msgstr "Löschung von BOM-Position bestätigen"
-#: report/models.py:153
+#: report/api.py:151
+msgid "No valid objects provided to template"
+msgstr ""
+
+#: report/models.py:163
#, fuzzy
#| msgid "Template part"
msgid "Template name"
msgstr "Vorlagenteil"
-#: report/models.py:160
+#: report/models.py:169
msgid "Report template file"
msgstr ""
-#: report/models.py:167
+#: report/models.py:176
#, fuzzy
#| msgid "Supplier part description"
msgid "Report template description"
msgstr "Zuliefererbeschreibung des Teils"
-#: report/models.py:173
+#: report/models.py:182
+msgid "Report revision number (auto-increments)"
+msgstr ""
+
+#: report/models.py:258
#, fuzzy
#| msgid "Supplier part description"
msgid "Report template is enabled"
msgstr "Zuliefererbeschreibung des Teils"
-#: report/models.py:195
-msgid "Part query filters (comma-separated list of key=value pairs)"
+#: report/models.py:278
+msgid "StockItem query filters (comma-separated list of key=value pairs)"
msgstr ""
-#: report/models.py:244
+#: report/models.py:324
+#, fuzzy
+#| msgid "Build Notes"
+msgid "Build Filters"
+msgstr "Bau-Bemerkungen"
+
+#: report/models.py:325
+msgid "Build query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:361
+#, fuzzy
+#| msgid "Part Notes"
+msgid "Part Filters"
+msgstr "Teil-Bemerkungen"
+
+#: report/models.py:362
+msgid "Part query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:407
+msgid "Report snippet file"
+msgstr ""
+
+#: report/models.py:411
+#, fuzzy
+#| msgid "Settings description"
+msgid "Snippet file description"
+msgstr "Einstellungs-Beschreibung"
+
+#: report/models.py:446
msgid "Report asset file"
msgstr ""
-#: report/models.py:247
+#: report/models.py:449
#, fuzzy
#| msgid "Settings description"
msgid "Asset file description"
msgstr "Einstellungs-Beschreibung"
+#: report/templates/report/inventree_build_order_base.html:149
+#, fuzzy
+#| msgid "Required"
+msgid "Required For"
+msgstr "benötigt"
+
+#: report/templates/report/inventree_test_report_base.html:21
+#, fuzzy
+#| msgid "StockItem is lost"
+msgid "Stock Item Test Report"
+msgstr "Lagerobjekt verloren"
+
+#: report/templates/report/inventree_test_report_base.html:83
+#, fuzzy
+#| msgid "Edit Template"
+msgid "Test Results"
+msgstr "Vorlage bearbeiten"
+
+#: report/templates/report/inventree_test_report_base.html:88
+#: stock/models.py:1557
+msgid "Test"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:89
+#: stock/models.py:1563
+#, fuzzy
+#| msgid "Search Results"
+msgid "Result"
+msgstr "Suchergebnisse"
+
+#: report/templates/report/inventree_test_report_base.html:92
+#: templates/js/order.js:193 templates/js/stock.js:862
+msgid "Date"
+msgstr "Datum"
+
+#: report/templates/report/inventree_test_report_base.html:103
+msgid "Pass"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:105
+msgid "Fail"
+msgstr ""
+
#: stock/forms.py:117
msgid "Enter unique serial numbers (or leave blank)"
msgstr "Eindeutige Seriennummern eingeben (oder leer lassen)"
@@ -4493,272 +4661,268 @@ msgstr "Standard-Lagerort"
msgid "Set the destination as the default location for selected parts"
msgstr "Setze das Ziel als Standard-Ziel für ausgewählte Teile"
-#: stock/models.py:200
+#: stock/models.py:203
#, fuzzy
#| msgid "Created new stock item"
msgid "Created stock item"
msgstr "Neues Lagerobjekt erstellt"
-#: stock/models.py:236
+#: stock/models.py:239
#, fuzzy
#| msgid "A stock item with this serial number already exists"
msgid "StockItem with this serial number already exists"
msgstr "Ein Teil mit dieser Seriennummer existiert bereits"
-#: stock/models.py:272
+#: stock/models.py:275
#, python-brace-format
msgid "Part type ('{pf}') must be {pe}"
msgstr "Teile-Typ ('{pf}') muss {pe} sein"
-#: stock/models.py:282 stock/models.py:291
+#: stock/models.py:285 stock/models.py:294
msgid "Quantity must be 1 for item with a serial number"
msgstr "Anzahl muss für Objekte mit Seriennummer \"1\" sein"
-#: stock/models.py:283
+#: stock/models.py:286
msgid "Serial number cannot be set if quantity greater than 1"
msgstr ""
"Seriennummer kann nicht gesetzt werden wenn die Anzahl größer als \"1\" ist"
-#: stock/models.py:305
+#: stock/models.py:308
msgid "Item cannot belong to itself"
msgstr "Teil kann nicht zu sich selbst gehören"
-#: stock/models.py:311
+#: stock/models.py:314
msgid "Item must have a build reference if is_building=True"
msgstr ""
-#: stock/models.py:318
+#: stock/models.py:321
msgid "Build reference does not point to the same part object"
msgstr ""
-#: stock/models.py:358
+#: stock/models.py:361
msgid "Parent Stock Item"
msgstr "Eltern-Lagerobjekt"
-#: stock/models.py:367
+#: stock/models.py:370
msgid "Base part"
msgstr "Basis-Teil"
-#: stock/models.py:376
+#: stock/models.py:379
msgid "Select a matching supplier part for this stock item"
msgstr "Passenden Zulieferer für dieses Lagerobjekt auswählen"
-#: stock/models.py:381 stock/templates/stock/stock_app_base.html:7
+#: stock/models.py:384 stock/templates/stock/stock_app_base.html:7
msgid "Stock Location"
msgstr "Lagerort"
-#: stock/models.py:384
+#: stock/models.py:387
msgid "Where is this stock item located?"
msgstr "Wo wird dieses Teil normalerweise gelagert?"
-#: stock/models.py:389 stock/templates/stock/item_base.html:253
+#: stock/models.py:392 stock/templates/stock/item_base.html:249
msgid "Installed In"
msgstr "Installiert in"
-#: stock/models.py:392
+#: stock/models.py:395
msgid "Is this item installed in another item?"
msgstr "Ist dieses Teil in einem anderen verbaut?"
-#: stock/models.py:408
+#: stock/models.py:411
msgid "Serial number for this item"
msgstr "Seriennummer für dieses Teil"
-#: stock/models.py:420
+#: stock/models.py:423
msgid "Batch code for this stock item"
msgstr "Losnummer für dieses Lagerobjekt"
-#: stock/models.py:424
+#: stock/models.py:427
msgid "Stock Quantity"
msgstr "Bestand"
-#: stock/models.py:433
+#: stock/models.py:436
msgid "Source Build"
msgstr "Quellbau"
-#: stock/models.py:435
+#: stock/models.py:438
msgid "Build for this stock item"
msgstr "Bau für dieses Lagerobjekt"
-#: stock/models.py:446
+#: stock/models.py:449
msgid "Source Purchase Order"
msgstr "Quellbestellung"
-#: stock/models.py:449
+#: stock/models.py:452
msgid "Purchase order for this stock item"
msgstr "Bestellung für dieses Teil"
-#: stock/models.py:455
+#: stock/models.py:458
msgid "Destination Sales Order"
msgstr "Zielauftrag"
-#: stock/models.py:461 stock/templates/stock/item_base.html:340
+#: stock/models.py:464 stock/templates/stock/item_base.html:336
#: templates/js/stock.js:613
#, fuzzy
#| msgid "Export"
msgid "Expiry Date"
msgstr "Exportieren"
-#: stock/models.py:462
+#: stock/models.py:465
msgid ""
"Expiry date for stock item. Stock will be considered expired after this date"
msgstr ""
-#: stock/models.py:475
+#: stock/models.py:478
msgid "Delete this Stock Item when stock is depleted"
msgstr "Objekt löschen wenn Lagerbestand aufgebraucht"
-#: stock/models.py:485 stock/templates/stock/item_notes.html:14
+#: stock/models.py:488 stock/templates/stock/item_notes.html:14
#: stock/templates/stock/item_notes.html:30
msgid "Stock Item Notes"
msgstr "Lagerobjekt-Notizen"
-#: stock/models.py:495
+#: stock/models.py:498
msgid "Single unit purchase price at time of purchase"
msgstr ""
-#: stock/models.py:599
+#: stock/models.py:602
#, fuzzy
#| msgid "Item assigned to customer?"
msgid "Assigned to Customer"
msgstr "Ist dieses Objekt einem Kunden zugeteilt?"
-#: stock/models.py:601
+#: stock/models.py:604
#, fuzzy
#| msgid "Item assigned to customer?"
msgid "Manually assigned to customer"
msgstr "Ist dieses Objekt einem Kunden zugeteilt?"
-#: stock/models.py:614
+#: stock/models.py:617
#, fuzzy
#| msgid "Item assigned to customer?"
msgid "Returned from customer"
msgstr "Ist dieses Objekt einem Kunden zugeteilt?"
-#: stock/models.py:616
+#: stock/models.py:619
#, fuzzy
#| msgid "Create new stock location"
msgid "Returned to location"
msgstr "Neuen Lagerort anlegen"
-#: stock/models.py:741
+#: stock/models.py:744
#, fuzzy
#| msgid "Installed in Stock Item"
msgid "Installed into stock item"
msgstr "In Lagerobjekt installiert"
-#: stock/models.py:749
+#: stock/models.py:752
#, fuzzy
#| msgid "Installed in Stock Item"
msgid "Installed stock item"
msgstr "In Lagerobjekt installiert"
-#: stock/models.py:773
+#: stock/models.py:776
#, fuzzy
#| msgid "Installed in Stock Item"
msgid "Uninstalled stock item"
msgstr "In Lagerobjekt installiert"
-#: stock/models.py:792
+#: stock/models.py:795
#, fuzzy
#| msgid "Include sublocations"
msgid "Uninstalled into location"
msgstr "Unterlagerorte einschließen"
-#: stock/models.py:872
+#: stock/models.py:875
#, fuzzy
#| msgid "Part is not a virtual part"
msgid "Part is not set as trackable"
msgstr "Teil ist nicht virtuell"
-#: stock/models.py:878
+#: stock/models.py:881
msgid "Quantity must be integer"
msgstr "Anzahl muss eine Ganzzahl sein"
-#: stock/models.py:884
+#: stock/models.py:887
#, python-brace-format
msgid "Quantity must not exceed available stock quantity ({n})"
msgstr "Anzahl darf nicht die verfügbare Anzahl überschreiten ({n})"
-#: stock/models.py:887
+#: stock/models.py:890
msgid "Serial numbers must be a list of integers"
msgstr "Seriennummern muss eine Liste von Ganzzahlen sein"
-#: stock/models.py:890
+#: stock/models.py:893
msgid "Quantity does not match serial numbers"
msgstr "Anzahl stimmt nicht mit den Seriennummern überein"
-#: stock/models.py:922
+#: stock/models.py:925
msgid "Add serial number"
msgstr "Seriennummer hinzufügen"
-#: stock/models.py:925
+#: stock/models.py:928
#, python-brace-format
msgid "Serialized {n} items"
msgstr "{n} Teile serialisiert"
-#: stock/models.py:1036
+#: stock/models.py:1006
+#, fuzzy
+#| msgid "Select from existing images"
+msgid "Split from existing stock"
+msgstr "Aus vorhandenen Bildern auswählen"
+
+#: stock/models.py:1044
msgid "StockItem cannot be moved as it is not in stock"
msgstr "Lagerobjekt kann nicht bewegt werden, da kein Bestand vorhanden ist"
-#: stock/models.py:1442
+#: stock/models.py:1470
msgid "Tracking entry title"
msgstr "Name des Eintrags-Trackings"
-#: stock/models.py:1444
+#: stock/models.py:1472
msgid "Entry notes"
msgstr "Eintrags-Notizen"
-#: stock/models.py:1446
+#: stock/models.py:1474
msgid "Link to external page for further information"
msgstr "Link auf externe Seite für weitere Informationen"
-#: stock/models.py:1506
+#: stock/models.py:1534
#, fuzzy
#| msgid "Serial number for this item"
msgid "Value must be provided for this test"
msgstr "Seriennummer für dieses Teil"
-#: stock/models.py:1512
+#: stock/models.py:1540
msgid "Attachment must be uploaded for this test"
msgstr ""
-#: stock/models.py:1529
-msgid "Test"
-msgstr ""
-
-#: stock/models.py:1530
+#: stock/models.py:1558
#, fuzzy
#| msgid "Part name"
msgid "Test name"
msgstr "Name des Teils"
-#: stock/models.py:1535
-#, fuzzy
-#| msgid "Search Results"
-msgid "Result"
-msgstr "Suchergebnisse"
-
-#: stock/models.py:1536 templates/js/table_filters.js:172
+#: stock/models.py:1564 templates/js/table_filters.js:172
msgid "Test result"
msgstr ""
-#: stock/models.py:1542
+#: stock/models.py:1570
msgid "Test output value"
msgstr ""
-#: stock/models.py:1548
+#: stock/models.py:1576
#, fuzzy
#| msgid "Attachments"
msgid "Attachment"
msgstr "Anhänge"
-#: stock/models.py:1549
+#: stock/models.py:1577
#, fuzzy
#| msgid "Delete attachment"
msgid "Test result attachment"
msgstr "Anhang löschen"
-#: stock/models.py:1555
+#: stock/models.py:1583
#, fuzzy
#| msgid "Edit notes"
msgid "Test notes"
@@ -4830,12 +4994,12 @@ msgstr ""
"aufgebraucht ist."
#: stock/templates/stock/item_base.html:91
-#: stock/templates/stock/item_base.html:344 templates/js/table_filters.js:111
+#: stock/templates/stock/item_base.html:340 templates/js/table_filters.js:111
msgid "Expired"
msgstr ""
#: stock/templates/stock/item_base.html:95
-#: stock/templates/stock/item_base.html:346 templates/js/table_filters.js:116
+#: stock/templates/stock/item_base.html:342 templates/js/table_filters.js:116
msgid "Stale"
msgstr ""
@@ -4854,147 +5018,147 @@ msgstr ""
msgid "Scan to Location"
msgstr "Lagerort"
-#: stock/templates/stock/item_base.html:144
+#: stock/templates/stock/item_base.html:143
#, fuzzy
#| msgid "Source Location"
msgid "Printing actions"
msgstr "Quell-Standort"
-#: stock/templates/stock/item_base.html:150
+#: stock/templates/stock/item_base.html:147
#: stock/templates/stock/item_tests.html:25
msgid "Test Report"
msgstr ""
-#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/item_base.html:156
#, fuzzy
#| msgid "Confirm stock adjustment"
msgid "Stock adjustment actions"
msgstr "Bestands-Anpassung bestätigen"
-#: stock/templates/stock/item_base.html:164
-#: stock/templates/stock/location.html:60 templates/stock_table.html:53
+#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/location.html:59 templates/stock_table.html:55
msgid "Count stock"
msgstr "Bestand zählen"
-#: stock/templates/stock/item_base.html:165 templates/stock_table.html:51
+#: stock/templates/stock/item_base.html:161 templates/stock_table.html:53
msgid "Add stock"
msgstr "Bestand hinzufügen"
-#: stock/templates/stock/item_base.html:166 templates/stock_table.html:52
+#: stock/templates/stock/item_base.html:162 templates/stock_table.html:54
msgid "Remove stock"
msgstr "Bestand entfernen"
-#: stock/templates/stock/item_base.html:168
+#: stock/templates/stock/item_base.html:164
#, fuzzy
#| msgid "Order stock"
msgid "Transfer stock"
msgstr "Bestand bestellen"
-#: stock/templates/stock/item_base.html:170
+#: stock/templates/stock/item_base.html:166
#, fuzzy
#| msgid "Serialize Stock"
msgid "Serialize stock"
msgstr "Lagerbestand erfassen"
-#: stock/templates/stock/item_base.html:174
+#: stock/templates/stock/item_base.html:170
#, fuzzy
#| msgid "Item assigned to customer?"
msgid "Assign to customer"
msgstr "Ist dieses Objekt einem Kunden zugeteilt?"
-#: stock/templates/stock/item_base.html:177
+#: stock/templates/stock/item_base.html:173
#, fuzzy
#| msgid "Count stock"
msgid "Return to stock"
msgstr "Bestand zählen"
-#: stock/templates/stock/item_base.html:181 templates/js/stock.js:1177
+#: stock/templates/stock/item_base.html:177 templates/js/stock.js:1177
#, fuzzy
#| msgid "Installed in Stock Item"
msgid "Uninstall stock item"
msgstr "In Lagerobjekt installiert"
-#: stock/templates/stock/item_base.html:181
+#: stock/templates/stock/item_base.html:177
msgid "Uninstall"
msgstr ""
-#: stock/templates/stock/item_base.html:190
-#: stock/templates/stock/location.html:57
+#: stock/templates/stock/item_base.html:186
+#: stock/templates/stock/location.html:56
#, fuzzy
#| msgid "Stock Locations"
msgid "Stock actions"
msgstr "Lagerobjekt-Standorte"
-#: stock/templates/stock/item_base.html:193
+#: stock/templates/stock/item_base.html:189
#, fuzzy
#| msgid "Count stock items"
msgid "Convert to variant"
msgstr "Lagerobjekte zählen"
-#: stock/templates/stock/item_base.html:196
+#: stock/templates/stock/item_base.html:192
#, fuzzy
#| msgid "Count stock items"
msgid "Duplicate stock item"
msgstr "Lagerobjekte zählen"
-#: stock/templates/stock/item_base.html:198
+#: stock/templates/stock/item_base.html:194
#, fuzzy
#| msgid "Edit Stock Item"
msgid "Edit stock item"
msgstr "Lagerobjekt bearbeiten"
-#: stock/templates/stock/item_base.html:201
+#: stock/templates/stock/item_base.html:197
#, fuzzy
#| msgid "Delete Stock Item"
msgid "Delete stock item"
msgstr "Lagerobjekt löschen"
-#: stock/templates/stock/item_base.html:213
+#: stock/templates/stock/item_base.html:209
msgid "Stock Item Details"
msgstr "Lagerbestands-Details"
-#: stock/templates/stock/item_base.html:272 templates/js/build.js:442
+#: stock/templates/stock/item_base.html:268 templates/js/build.js:442
#, fuzzy
#| msgid "No stock location set"
msgid "No location set"
msgstr "Kein Lagerort gesetzt"
-#: stock/templates/stock/item_base.html:279
+#: stock/templates/stock/item_base.html:275
#, fuzzy
#| msgid "Unique Identifier"
msgid "Barcode Identifier"
msgstr "Eindeutiger Bezeichner"
-#: stock/templates/stock/item_base.html:293 templates/js/build.js:642
-#: templates/navbar.html:25
+#: stock/templates/stock/item_base.html:289 templates/js/build.js:648
+#: templates/navbar.html:29
msgid "Build"
msgstr "Bau"
-#: stock/templates/stock/item_base.html:314
+#: stock/templates/stock/item_base.html:310
msgid "Parent Item"
msgstr "Elternposition"
-#: stock/templates/stock/item_base.html:344
+#: stock/templates/stock/item_base.html:340
#, fuzzy
#| msgid "This stock item is allocated to Build"
msgid "This StockItem expired on"
msgstr "Dieses Lagerobjekt ist dem Bau zugewiesen"
-#: stock/templates/stock/item_base.html:346
+#: stock/templates/stock/item_base.html:342
#, fuzzy
#| msgid "Child Stock Items"
msgid "This StockItem expires on"
msgstr "Kind-Lagerobjekte"
-#: stock/templates/stock/item_base.html:353 templates/js/stock.js:619
+#: stock/templates/stock/item_base.html:349 templates/js/stock.js:619
msgid "Last Updated"
msgstr "Zuletzt aktualisiert"
-#: stock/templates/stock/item_base.html:358
+#: stock/templates/stock/item_base.html:354
msgid "Last Stocktake"
msgstr "Letzte Inventur"
-#: stock/templates/stock/item_base.html:362
+#: stock/templates/stock/item_base.html:358
msgid "No stocktake performed"
msgstr "Keine Inventur ausgeführt"
@@ -5072,58 +5236,58 @@ msgstr ""
msgid "All stock items"
msgstr "Alle Lagerobjekte"
-#: stock/templates/stock/location.html:49
+#: stock/templates/stock/location.html:48
#, fuzzy
#| msgid "Child Stock Items"
msgid "Check-in Items"
msgstr "Kind-Lagerobjekte"
-#: stock/templates/stock/location.html:66
+#: stock/templates/stock/location.html:65
#, fuzzy
#| msgid "Location Description"
msgid "Location actions"
msgstr "Standort-Beschreibung"
-#: stock/templates/stock/location.html:68
+#: stock/templates/stock/location.html:67
#, fuzzy
#| msgid "Edit stock location"
msgid "Edit location"
msgstr "Lagerort bearbeiten"
-#: stock/templates/stock/location.html:70
+#: stock/templates/stock/location.html:69
#, fuzzy
#| msgid "Delete stock location"
msgid "Delete location"
msgstr "Lagerort löschen"
-#: stock/templates/stock/location.html:81
+#: stock/templates/stock/location.html:80
msgid "Location Details"
msgstr "Standort-Details"
-#: stock/templates/stock/location.html:86
+#: stock/templates/stock/location.html:85
msgid "Location Path"
msgstr "Standord-Pfad"
-#: stock/templates/stock/location.html:91
+#: stock/templates/stock/location.html:90
msgid "Location Description"
msgstr "Standort-Beschreibung"
-#: stock/templates/stock/location.html:96
+#: stock/templates/stock/location.html:95
msgid "Sublocations"
msgstr "Sub-Standorte"
-#: stock/templates/stock/location.html:101
-#: stock/templates/stock/location.html:116
+#: stock/templates/stock/location.html:100
+#: stock/templates/stock/location.html:115
#: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48
#: templates/stats.html:57 users/models.py:35
msgid "Stock Items"
msgstr "Lagerobjekte"
-#: stock/templates/stock/location.html:106
+#: stock/templates/stock/location.html:105
msgid "Stock Details"
msgstr "Objekt-Details"
-#: stock/templates/stock/location.html:111
+#: stock/templates/stock/location.html:110
#: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52
#: users/models.py:34
msgid "Stock Locations"
@@ -5327,15 +5491,11 @@ msgstr "Anzahl muss positiv sein"
msgid "Quantity must not exceed {x}"
msgstr "Anzahl darf {x} nicht überschreiten"
-#: stock/views.py:1132
-#, python-brace-format
-msgid "Added stock to {n} items"
-msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt"
-
-#: stock/views.py:1147
-#, python-brace-format
-msgid "Removed stock from {n} items"
-msgstr "Vorrat von {n} Lagerobjekten entfernt"
+#: stock/views.py:1117
+#, fuzzy
+#| msgid "No action specified"
+msgid "No action performed"
+msgstr "Keine Aktion angegeben"
#: stock/views.py:1160
#, python-brace-format
@@ -5548,7 +5708,7 @@ msgstr "Vorlage löschen"
msgid "Global InvenTree Settings"
msgstr "InvenTree-Version"
-#: templates/InvenTree/settings/global.html:24
+#: templates/InvenTree/settings/global.html:25
#, fuzzy
#| msgid "Source Location"
msgid "Barcode Settings"
@@ -5588,6 +5748,12 @@ msgstr "Keine Teilparametervorlagen gefunden"
msgid "Purchase Order Settings"
msgstr "Bestelldetails"
+#: templates/InvenTree/settings/report.html:10
+#, fuzzy
+#| msgid "Settings"
+msgid "Report Settings"
+msgstr "Einstellungen"
+
#: templates/InvenTree/settings/setting.html:23
msgid "No value set"
msgstr ""
@@ -5599,7 +5765,7 @@ msgid "Edit setting"
msgstr "Einstellungen"
#: templates/InvenTree/settings/settings.html:7
-#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:66
+#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:76
msgid "Settings"
msgstr "Einstellungen"
@@ -5615,7 +5781,7 @@ msgstr "Auftragsdetails"
msgid "Stock Settings"
msgstr "Lagerobjekt-Standorte"
-#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:46
+#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:48
#, fuzzy
#| msgid "Stock Locations"
msgid "Stock Options"
@@ -5648,6 +5814,12 @@ msgstr ""
#: templates/InvenTree/settings/tabs.html:19
#, fuzzy
+#| msgid "Export"
+msgid "Report"
+msgstr "Exportieren"
+
+#: templates/InvenTree/settings/tabs.html:22
+#, fuzzy
#| msgid "Part Categories"
msgid "Categories"
msgstr "Teile-Kategorien"
@@ -5685,6 +5857,7 @@ msgid "Change Password"
msgstr "Neues Teil anlegen"
#: templates/InvenTree/settings/user.html:28
+#: templates/registration/login.html:58
#, fuzzy
#| msgid "User"
msgid "Username"
@@ -6007,7 +6180,7 @@ msgstr "Anzahl"
msgid "Build stock"
msgstr "Baue"
-#: templates/js/build.js:582 templates/stock_table.html:55
+#: templates/js/build.js:582 templates/stock_table.html:57
msgid "Order stock"
msgstr "Bestand bestellen"
@@ -6019,13 +6192,18 @@ msgstr "Lagerbestand zuweisen"
msgid "No builds matching query"
msgstr "Keine Baue passen zur Anfrage"
-#: templates/js/build.js:656
+#: templates/js/build.js:642 templates/js/part.js:343 templates/js/stock.js:474
+#: templates/js/stock.js:1209
+msgid "Select"
+msgstr "Auswählen"
+
+#: templates/js/build.js:662
#, fuzzy
#| msgid "Build order allocation is complete"
msgid "Build order is overdue"
msgstr "Bau-Zuweisung ist vollständig"
-#: templates/js/build.js:747
+#: templates/js/build.js:760
msgid "No parts allocated for"
msgstr "Keine Teile zugeordnet zu"
@@ -6057,7 +6235,7 @@ msgstr "Vorlagenteil"
msgid "Assembled part"
msgstr "Baugruppe"
-#: templates/js/label.js:10 templates/js/report.js:89
+#: templates/js/label.js:10 templates/js/report.js:98
#, fuzzy
#| msgid "Delete Stock Items"
msgid "Select Stock Items"
@@ -6095,13 +6273,13 @@ msgstr ""
msgid "No labels found which match selected stock location(s)"
msgstr ""
-#: templates/js/label.js:142 templates/js/report.js:38
+#: templates/js/label.js:142
#, fuzzy
#| msgid "StockItem has been allocated"
msgid "stock items selected"
msgstr "Lagerobjekt wurde zugewiesen"
-#: templates/js/label.js:150 templates/js/report.js:46
+#: templates/js/label.js:150
#, fuzzy
#| msgid "Select valid part"
msgid "Select Label"
@@ -6119,11 +6297,11 @@ msgstr "Bitte ein gültiges Teil auswählen"
msgid "Show Error Information"
msgstr "Kosteninformationen ansehen"
-#: templates/js/modals.js:473
+#: templates/js/modals.js:473 templates/modals.html:64
msgid "Accept"
msgstr ""
-#: templates/js/modals.js:474
+#: templates/js/modals.js:474 templates/modals.html:63
#, fuzzy
#| msgid "Cancelled"
msgid "Cancel"
@@ -6134,14 +6312,14 @@ msgid "Loading Data"
msgstr ""
#: templates/js/modals.js:549 templates/js/modals.js:807
-#: templates/modals.html:19 templates/modals.html:41
+#: templates/modals.html:22 templates/modals.html:44
#, fuzzy
#| msgid "Edit BOM"
msgid "Submit"
msgstr "Stückliste bearbeiten"
#: templates/js/modals.js:550 templates/js/modals.js:808
-#: templates/modals.html:18 templates/modals.html:40
+#: templates/modals.html:21 templates/modals.html:43 templates/modals.html:82
msgid "Close"
msgstr ""
@@ -6229,10 +6407,6 @@ msgstr "Keine Bestellungen gefunden"
msgid "Order is overdue"
msgstr "Bau-Zuweisung ist vollständig"
-#: templates/js/order.js:193 templates/js/stock.js:862
-msgid "Date"
-msgstr "Datum"
-
#: templates/js/order.js:229
msgid "No sales orders found"
msgstr "Keine Aufträge gefunden"
@@ -6271,11 +6445,6 @@ msgstr "Keine Teile gefunden"
msgid "No parts found"
msgstr "Keine Teile gefunden"
-#: templates/js/part.js:343 templates/js/stock.js:474
-#: templates/js/stock.js:1209
-msgid "Select"
-msgstr "Auswählen"
-
#: templates/js/part.js:411
msgid "No category"
msgstr "Keine Kategorie"
@@ -6318,30 +6487,79 @@ msgstr "Anhang löschen"
msgid "This test is defined for a parent part"
msgstr ""
-#: templates/js/report.js:61
+#: templates/js/report.js:47
+#, fuzzy
+#| msgid "StockItem has been allocated"
+msgid "items selected"
+msgstr "Lagerobjekt wurde zugewiesen"
+
+#: templates/js/report.js:55
+#, fuzzy
+#| msgid "Delete Template"
+msgid "Select Report Template"
+msgstr "Vorlage löschen"
+
+#: templates/js/report.js:70
#, fuzzy
#| msgid "Delete Template"
msgid "Select Test Report Template"
msgstr "Vorlage löschen"
-#: templates/js/report.js:90
+#: templates/js/report.js:99
#, fuzzy
#| msgid "StockItem has been allocated"
msgid "Stock item(s) must be selected before printing reports"
msgstr "Lagerobjekt wurde zugewiesen"
-#: templates/js/report.js:107
+#: templates/js/report.js:116 templates/js/report.js:169
+#: templates/js/report.js:223
#, fuzzy
#| msgid "No parts found"
msgid "No Reports Found"
msgstr "Keine Teile gefunden"
-#: templates/js/report.js:108
+#: templates/js/report.js:117
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "No report templates found which match selected stock item(s)"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
+#: templates/js/report.js:152
+#, fuzzy
+#| msgid "Delete Build"
+msgid "Select Builds"
+msgstr "Bau entfernt"
+
+#: templates/js/report.js:153
+#, fuzzy
+#| msgid "StockItem has been allocated"
+msgid "Build(s) must be selected before printing reports"
+msgstr "Lagerobjekt wurde zugewiesen"
+
+#: templates/js/report.js:170
+#, fuzzy
+#| msgid "Remove selected BOM items"
+msgid "No report templates found which match selected build(s)"
+msgstr "Ausgewählte Stücklistenpositionen entfernen"
+
+#: templates/js/report.js:205
+#, fuzzy
+#| msgid "Select part"
+msgid "Select Parts"
+msgstr "Teil auswählen"
+
+#: templates/js/report.js:206
+#, fuzzy
+#| msgid "StockItem has been allocated"
+msgid "Part(s) must be selected before printing reports"
+msgstr "Lagerobjekt wurde zugewiesen"
+
+#: templates/js/report.js:224
+#, fuzzy
+#| msgid "Remove selected BOM items"
+msgid "No report templates found which match selected part(s)"
+msgstr "Ausgewählte Stücklistenpositionen entfernen"
+
#: templates/js/stock.js:38
msgid "PASS"
msgstr ""
@@ -6699,99 +6917,121 @@ msgstr "Favorit"
msgid "Purchasable"
msgstr "Käuflich"
-#: templates/js/tables.js:276
+#: templates/js/tables.js:268
msgid "Loading data"
msgstr ""
-#: templates/js/tables.js:279
+#: templates/js/tables.js:271
msgid "rows per page"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "Showing"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "to"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "of"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "rows"
msgstr ""
-#: templates/js/tables.js:285 templates/search_form.html:6
+#: templates/js/tables.js:277 templates/search_form.html:6
#: templates/search_form.html:8
msgid "Search"
msgstr "Suche"
-#: templates/js/tables.js:288
+#: templates/js/tables.js:280
#, fuzzy
#| msgid "No matching action found"
msgid "No matching results"
msgstr "Keine passende Aktion gefunden"
-#: templates/js/tables.js:291
+#: templates/js/tables.js:283
#, fuzzy
#| msgid "Show pricing information"
msgid "Hide/Show pagination"
msgstr "Kosteninformationen ansehen"
-#: templates/js/tables.js:294
+#: templates/js/tables.js:286
msgid "Refresh"
msgstr ""
-#: templates/js/tables.js:297
+#: templates/js/tables.js:289
msgid "Toggle"
msgstr ""
-#: templates/js/tables.js:300
+#: templates/js/tables.js:292
msgid "Columns"
msgstr ""
-#: templates/js/tables.js:303
+#: templates/js/tables.js:295
msgid "All"
msgstr ""
-#: templates/modals.html:13 templates/modals.html:35
+#: templates/modals.html:14 templates/modals.html:38
msgid "Form errors exist"
msgstr ""
-#: templates/navbar.html:29
+#: templates/navbar.html:33
msgid "Buy"
msgstr "Kaufen"
-#: templates/navbar.html:39
+#: templates/navbar.html:43
msgid "Sell"
msgstr "Verkaufen"
-#: templates/navbar.html:50
+#: templates/navbar.html:55
msgid "Scan Barcode"
msgstr ""
-#: templates/navbar.html:57
+#: templates/navbar.html:63
msgid "InvenTree server issues detected"
msgstr ""
-#: templates/navbar.html:63 users/models.py:31
+#: templates/navbar.html:69 users/models.py:31
msgid "Admin"
msgstr "Admin"
-#: templates/navbar.html:67
+#: templates/navbar.html:71
msgid "Logout"
msgstr "Ausloggen"
-#: templates/navbar.html:69 templates/registration/login.html:43
+#: templates/navbar.html:73 templates/registration/login.html:89
msgid "Login"
msgstr "Einloggen"
-#: templates/navbar.html:80
+#: templates/navbar.html:85
msgid "About InvenTree"
msgstr "Über InvenBaum"
+#: templates/registration/login.html:64
+#, fuzzy
+#| msgid "Entry notes"
+msgid "Enter username"
+msgstr "Eintrags-Notizen"
+
+#: templates/registration/login.html:70
+#, fuzzy
+#| msgid "Select part"
+msgid "Password"
+msgstr "Teil auswählen"
+
+#: templates/registration/login.html:76
+#, fuzzy
+#| msgid "Create new part"
+msgid "Enter password"
+msgstr "Neues Teil anlegen"
+
+#: templates/registration/login.html:83
+msgid "Username / password combination is incorrect"
+msgstr ""
+
#: templates/stats.html:9
msgid "Server"
msgstr ""
@@ -6838,65 +7078,65 @@ msgstr "Quell-Standort"
msgid "Print labels"
msgstr ""
-#: templates/stock_table.html:41
+#: templates/stock_table.html:42
#, fuzzy
#| msgid "Parameter Template"
msgid "Print test reports"
msgstr "Parameter Vorlage"
-#: templates/stock_table.html:51
+#: templates/stock_table.html:53
#, fuzzy
#| msgid "Added stock to {n} items"
msgid "Add to selected stock items"
msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt"
-#: templates/stock_table.html:52
+#: templates/stock_table.html:54
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "Remove from selected stock items"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
-#: templates/stock_table.html:53
+#: templates/stock_table.html:55
#, fuzzy
#| msgid "Delete Stock Item"
msgid "Stocktake selected stock items"
msgstr "Lagerobjekt löschen"
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
#, fuzzy
#| msgid "Delete Stock Item"
msgid "Move selected stock items"
msgstr "Lagerobjekt löschen"
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
msgid "Move stock"
msgstr "Bestand bewegen"
-#: templates/stock_table.html:55
+#: templates/stock_table.html:57
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "Order selected items"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
#, fuzzy
#| msgid "Settings"
msgid "Change status"
msgstr "Einstellungen"
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
#, fuzzy
#| msgid "Stock status"
msgid "Change stock status"
msgstr "Bestandsstatus"
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
#, fuzzy
#| msgid "Delete line item"
msgid "Delete selected items"
msgstr "Position löschen"
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
msgid "Delete Stock"
msgstr "Bestand löschen"
@@ -6932,46 +7172,72 @@ msgstr "Revision"
msgid "Important dates"
msgstr "Stückliste importieren"
-#: users/models.py:147
+#: users/models.py:150
msgid "Permission set"
msgstr ""
-#: users/models.py:155
+#: users/models.py:158
msgid "Group"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "View"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "Permission to view items"
msgstr ""
-#: users/models.py:160
+#: users/models.py:163
#, fuzzy
#| msgid "Address"
msgid "Add"
msgstr "Adresse"
-#: users/models.py:160
+#: users/models.py:163
msgid "Permission to add items"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Change"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Permissions to edit items"
msgstr ""
-#: users/models.py:164
+#: users/models.py:167
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "Permission to delete items"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
+#, fuzzy
+#~| msgid "Parameters"
+#~ msgid "Copy from Parent"
+#~ msgstr "Parameter"
+
+#, fuzzy
+#~| msgid "Add Line Item"
+#~ msgid "Add Item"
+#~ msgstr "Position hinzufügen"
+
+#, fuzzy
+#~| msgid "Finish Editing"
+#~ msgid "Finished"
+#~ msgstr "Bearbeitung beenden"
+
+#, fuzzy
+#~| msgid "Validate BOM"
+#~ msgid "Validate"
+#~ msgstr "BOM validieren"
+
+#~ msgid "Added stock to {n} items"
+#~ msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt"
+
+#~ msgid "Removed stock from {n} items"
+#~ msgstr "Vorrat von {n} Lagerobjekten entfernt"
+
#, fuzzy
#~| msgid "Confirm stock adjustment"
#~ msgid "Document actions"
@@ -7168,11 +7434,6 @@ msgstr "Ausgewählte Stücklistenpositionen entfernen"
#~ msgid "Invalid SupplierPart selection"
#~ msgstr "Ungültige Wahl des Zulieferer-Teils"
-#, fuzzy
-#~| msgid "This stock item is allocated to Sales Order"
-#~ msgid "Stock item was assigned to a build order"
-#~ msgstr "Dieses Lagerobjekt ist dem Auftrag zugewiesen"
-
#, fuzzy
#~| msgid "Template part"
#~ msgid "Templat part"
diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po
index 4236df6f39..c7eadc80ac 100644
--- a/InvenTree/locale/en/LC_MESSAGES/django.po
+++ b/InvenTree/locale/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-01-29 12:04+1100\n"
+"POT-Creation-Date: 2021-02-16 22:33+1100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -30,7 +30,7 @@ msgstr ""
msgid "Enter date"
msgstr ""
-#: InvenTree/forms.py:110 build/forms.py:90 build/forms.py:178
+#: InvenTree/forms.py:110 build/forms.py:92 build/forms.py:180
msgid "Confirm"
msgstr ""
@@ -95,12 +95,14 @@ msgstr ""
msgid "File comment"
msgstr ""
-#: InvenTree/models.py:68 templates/js/stock.js:919
+#: InvenTree/models.py:68
+#: report/templates/report/inventree_test_report_base.html:91
+#: templates/js/stock.js:919
msgid "User"
msgstr ""
-#: InvenTree/models.py:106 label/models.py:68 part/models.py:654
-#: part/templates/part/params.html:24 report/models.py:152
+#: InvenTree/models.py:106 label/models.py:69 part/models.py:654
+#: part/templates/part/params.html:24 report/models.py:162
#: templates/js/part.js:129
msgid "Name"
msgstr ""
@@ -109,23 +111,23 @@ msgstr ""
msgid "Description (optional)"
msgstr ""
-#: InvenTree/settings.py:454
+#: InvenTree/settings.py:446
msgid "English"
msgstr ""
-#: InvenTree/settings.py:455
+#: InvenTree/settings.py:447
msgid "French"
msgstr ""
-#: InvenTree/settings.py:456
+#: InvenTree/settings.py:448
msgid "German"
msgstr ""
-#: InvenTree/settings.py:457
+#: InvenTree/settings.py:449
msgid "Polish"
msgstr ""
-#: InvenTree/settings.py:458
+#: InvenTree/settings.py:450
msgid "Turkish"
msgstr ""
@@ -248,7 +250,7 @@ msgstr ""
msgid "Password fields must match"
msgstr ""
-#: InvenTree/views.py:795 templates/navbar.html:78
+#: InvenTree/views.py:795 templates/navbar.html:83
msgid "System Information"
msgstr ""
@@ -300,14 +302,14 @@ msgstr ""
msgid "Order target date"
msgstr ""
-#: build/forms.py:39 build/models.py:206
+#: build/forms.py:39 build/models.py:210
msgid ""
"Target date for build completion. Build will be overdue after this date."
msgstr ""
-#: build/forms.py:78 build/templates/build/auto_allocate.html:17
-#: build/templates/build/build_base.html:83
-#: build/templates/build/detail.html:29 common/models.py:610
+#: build/forms.py:80 build/templates/build/auto_allocate.html:17
+#: build/templates/build/build_base.html:91
+#: build/templates/build/detail.html:29 common/models.py:647
#: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75
#: order/templates/order/order_wizard/select_parts.html:32
#: order/templates/order/purchase_order_detail.html:179
@@ -315,285 +317,302 @@ msgstr ""
#: order/templates/order/sales_order_detail.html:156
#: part/templates/part/allocation.html:16
#: part/templates/part/allocation.html:49
-#: part/templates/part/sale_prices.html:82 stock/forms.py:306
-#: stock/templates/stock/item_base.html:51
+#: part/templates/part/sale_prices.html:82
+#: report/templates/report/inventree_build_order_base.html:116
+#: report/templates/report/inventree_test_report_base.html:77
+#: stock/forms.py:306 stock/templates/stock/item_base.html:51
#: stock/templates/stock/item_base.html:57
-#: stock/templates/stock/item_base.html:238
+#: stock/templates/stock/item_base.html:234
#: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364
#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:910
#: templates/js/stock.js:1149
msgid "Quantity"
msgstr ""
-#: build/forms.py:79
+#: build/forms.py:81
msgid "Enter quantity for build output"
msgstr ""
-#: build/forms.py:83 stock/forms.py:117
+#: build/forms.py:85 stock/forms.py:117
msgid "Serial numbers"
msgstr ""
-#: build/forms.py:85
+#: build/forms.py:87
msgid "Enter serial numbers for build outputs"
msgstr ""
-#: build/forms.py:91
+#: build/forms.py:93
msgid "Confirm creation of build outut"
msgstr ""
-#: build/forms.py:111
+#: build/forms.py:113
msgid "Confirm deletion of build output"
msgstr ""
-#: build/forms.py:132
+#: build/forms.py:134
msgid "Confirm unallocation of stock"
msgstr ""
-#: build/forms.py:156
+#: build/forms.py:158
msgid "Confirm stock allocation"
msgstr ""
-#: build/forms.py:179
+#: build/forms.py:181
msgid "Mark build as complete"
msgstr ""
-#: build/forms.py:203
+#: build/forms.py:205
msgid "Location of completed parts"
msgstr ""
-#: build/forms.py:208
+#: build/forms.py:210
msgid "Confirm completion with incomplete stock allocation"
msgstr ""
-#: build/forms.py:211
+#: build/forms.py:213
msgid "Confirm build completion"
msgstr ""
-#: build/forms.py:231 build/views.py:68
+#: build/forms.py:233 build/views.py:68
msgid "Confirm build cancellation"
msgstr ""
-#: build/forms.py:245
+#: build/forms.py:247
msgid "Select quantity of stock to allocate"
msgstr ""
-#: build/models.py:61 build/templates/build/build_base.html:8
+#: build/models.py:65 build/templates/build/build_base.html:8
#: build/templates/build/build_base.html:35
#: part/templates/part/allocation.html:20
+#: report/templates/report/inventree_build_order_base.html:108
msgid "Build Order"
msgstr ""
-#: build/models.py:62 build/templates/build/index.html:8
+#: build/models.py:66 build/templates/build/index.html:8
#: build/templates/build/index.html:15 order/templates/order/so_builds.html:11
#: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31
-#: templates/InvenTree/settings/tabs.html:28 users/models.py:36
+#: templates/InvenTree/settings/tabs.html:31 users/models.py:36
msgid "Build Orders"
msgstr ""
-#: build/models.py:108
+#: build/models.py:112
msgid "Build Order Reference"
msgstr ""
-#: build/models.py:109 order/templates/order/purchase_order_detail.html:174
+#: build/models.py:113 order/templates/order/purchase_order_detail.html:174
#: templates/js/bom.js:187 templates/js/build.js:509
msgid "Reference"
msgstr ""
-#: build/models.py:116 build/templates/build/detail.html:19
+#: build/models.py:120 build/templates/build/detail.html:19
#: company/models.py:359 company/templates/company/detail.html:23
#: company/templates/company/supplier_part_base.html:61
-#: company/templates/company/supplier_part_detail.html:27 label/models.py:75
+#: company/templates/company/supplier_part_detail.html:27 label/models.py:76
#: order/templates/order/purchase_order_detail.html:161 part/models.py:678
#: part/templates/part/detail.html:51 part/templates/part/set_category.html:14
-#: report/models.py:166 templates/InvenTree/search.html:147
+#: report/models.py:175
+#: report/templates/report/inventree_build_order_base.html:120
+#: templates/InvenTree/search.html:147
#: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180
-#: templates/js/bom.js:547 templates/js/build.js:664 templates/js/company.js:56
+#: templates/js/bom.js:547 templates/js/build.js:670 templates/js/company.js:56
#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188
#: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:586
#: templates/js/stock.js:512 templates/js/stock.js:891
msgid "Description"
msgstr ""
-#: build/models.py:119
+#: build/models.py:123
msgid "Brief description of the build"
msgstr ""
-#: build/models.py:128 build/templates/build/build_base.html:113
+#: build/models.py:132 build/templates/build/build_base.html:121
#: build/templates/build/detail.html:75
msgid "Parent Build"
msgstr ""
-#: build/models.py:129
+#: build/models.py:133
msgid "BuildOrder to which this build is allocated"
msgstr ""
-#: build/models.py:134 build/templates/build/auto_allocate.html:16
-#: build/templates/build/build_base.html:78
+#: build/models.py:138 build/templates/build/auto_allocate.html:16
+#: build/templates/build/build_base.html:86
#: build/templates/build/detail.html:24 order/models.py:652
#: order/templates/order/order_wizard/select_parts.html:30
#: order/templates/order/purchase_order_detail.html:148
#: order/templates/order/receive_parts.html:19 part/models.py:320
#: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26
-#: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133
-#: templates/js/barcode.js:362 templates/js/bom.js:153 templates/js/bom.js:532
-#: templates/js/build.js:669 templates/js/company.js:138
-#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:486
+#: part/templates/part/set_category.html:13
+#: report/templates/report/inventree_build_order_base.html:112
+#: templates/InvenTree/search.html:133 templates/js/barcode.js:362
+#: templates/js/bom.js:153 templates/js/bom.js:532 templates/js/build.js:675
+#: templates/js/company.js:138 templates/js/part.js:252
+#: templates/js/part.js:357 templates/js/stock.js:486
#: templates/js/stock.js:1221
msgid "Part"
msgstr ""
-#: build/models.py:142
+#: build/models.py:146
msgid "Select part to build"
msgstr ""
-#: build/models.py:147
+#: build/models.py:151
msgid "Sales Order Reference"
msgstr ""
-#: build/models.py:151
+#: build/models.py:155
msgid "SalesOrder to which this build is allocated"
msgstr ""
-#: build/models.py:156
+#: build/models.py:160
msgid "Source Location"
msgstr ""
-#: build/models.py:160
+#: build/models.py:164
msgid ""
"Select location to take stock from for this build (leave blank to take from "
"any stock location)"
msgstr ""
-#: build/models.py:165
+#: build/models.py:169
msgid "Destination Location"
msgstr ""
-#: build/models.py:169
+#: build/models.py:173
msgid "Select location where the completed items will be stored"
msgstr ""
-#: build/models.py:173
+#: build/models.py:177
msgid "Build Quantity"
msgstr ""
-#: build/models.py:176
+#: build/models.py:180
msgid "Number of stock items to build"
msgstr ""
-#: build/models.py:180
+#: build/models.py:184
msgid "Completed items"
msgstr ""
-#: build/models.py:182
+#: build/models.py:186
msgid "Number of stock items which have been completed"
msgstr ""
-#: build/models.py:186 part/templates/part/part_base.html:158
+#: build/models.py:190 part/templates/part/part_base.html:157
msgid "Build Status"
msgstr ""
-#: build/models.py:190
+#: build/models.py:194
msgid "Build status code"
msgstr ""
-#: build/models.py:194 stock/models.py:418
+#: build/models.py:198 stock/models.py:421
msgid "Batch Code"
msgstr ""
-#: build/models.py:198
+#: build/models.py:202
msgid "Batch code for this build output"
msgstr ""
-#: build/models.py:205 order/models.py:437
+#: build/models.py:209 order/models.py:437
msgid "Target completion date"
msgstr ""
-#: build/models.py:219 build/templates/build/detail.html:89
+#: build/models.py:226
+msgid "User who issued this build order"
+msgstr ""
+
+#: build/models.py:234
+msgid "User responsible for this build order"
+msgstr ""
+
+#: build/models.py:239 build/templates/build/detail.html:89
#: company/templates/company/supplier_part_base.html:68
#: company/templates/company/supplier_part_detail.html:24
-#: part/templates/part/detail.html:80 part/templates/part/part_base.html:105
-#: stock/models.py:412 stock/templates/stock/item_base.html:321
+#: part/templates/part/detail.html:80 part/templates/part/part_base.html:104
+#: stock/models.py:415 stock/templates/stock/item_base.html:317
msgid "External Link"
msgstr ""
-#: build/models.py:220 part/models.py:712 stock/models.py:414
+#: build/models.py:240 part/models.py:712 stock/models.py:417
msgid "Link to external URL"
msgstr ""
-#: build/models.py:224 build/templates/build/tabs.html:23 company/models.py:366
+#: build/models.py:244 build/templates/build/tabs.html:23 company/models.py:366
#: company/templates/company/tabs.html:33 order/templates/order/po_tabs.html:18
#: order/templates/order/purchase_order_detail.html:213
#: order/templates/order/so_tabs.html:23 part/models.py:838
-#: part/templates/part/tabs.html:73 stock/forms.py:315 stock/forms.py:347
-#: stock/forms.py:375 stock/models.py:484 stock/models.py:1554
-#: stock/templates/stock/tabs.html:26 templates/js/barcode.js:37
-#: templates/js/bom.js:293 templates/js/stock.js:128 templates/js/stock.js:624
+#: part/templates/part/tabs.html:73
+#: report/templates/report/inventree_build_order_base.html:175
+#: stock/forms.py:315 stock/forms.py:347 stock/forms.py:375 stock/models.py:487
+#: stock/models.py:1582 stock/templates/stock/tabs.html:26
+#: templates/js/barcode.js:37 templates/js/bom.js:293 templates/js/stock.js:128
+#: templates/js/stock.js:624
msgid "Notes"
msgstr ""
-#: build/models.py:225
+#: build/models.py:245
msgid "Extra build notes"
msgstr ""
-#: build/models.py:607
+#: build/models.py:627
msgid "No build output specified"
msgstr ""
-#: build/models.py:610
+#: build/models.py:630
msgid "Build output is already completed"
msgstr ""
-#: build/models.py:613
+#: build/models.py:633
msgid "Build output does not match Build Order"
msgstr ""
-#: build/models.py:688
+#: build/models.py:708
msgid "Completed build output"
msgstr ""
-#: build/models.py:930
+#: build/models.py:950
msgid "BuildItem must be unique for build, stock_item and install_into"
msgstr ""
-#: build/models.py:952
+#: build/models.py:972
msgid "Build item must specify a build output"
msgstr ""
-#: build/models.py:957
+#: build/models.py:977
#, python-brace-format
msgid "Selected stock item not found in BOM for part '{p}'"
msgstr ""
-#: build/models.py:961
+#: build/models.py:981
#, python-brace-format
msgid "Allocated quantity ({n}) must not exceed available quantity ({q})"
msgstr ""
-#: build/models.py:968 order/models.py:736
+#: build/models.py:988 order/models.py:736
msgid "StockItem is over-allocated"
msgstr ""
-#: build/models.py:972 order/models.py:739
+#: build/models.py:992 order/models.py:739
msgid "Allocation quantity must be greater than zero"
msgstr ""
-#: build/models.py:976
+#: build/models.py:996
msgid "Quantity must be 1 for serialized stock"
msgstr ""
-#: build/models.py:1016
+#: build/models.py:1036
msgid "Build to allocate parts"
msgstr ""
-#: build/models.py:1023
+#: build/models.py:1043
msgid "Source stock item"
msgstr ""
-#: build/models.py:1035
+#: build/models.py:1055
msgid "Stock quantity to allocate to build"
msgstr ""
-#: build/models.py:1043
+#: build/models.py:1063
msgid "Destination stock item"
msgstr ""
@@ -627,7 +646,7 @@ msgstr ""
msgid "Unallocate stock"
msgstr ""
-#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:778
+#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:781
msgid "Unallocate Stock"
msgstr ""
@@ -659,7 +678,7 @@ msgid ""
msgstr ""
#: build/templates/build/auto_allocate.html:18 stock/forms.py:345
-#: stock/templates/stock/item_base.html:268
+#: stock/templates/stock/item_base.html:264
#: stock/templates/stock/stock_adjust.html:17
#: templates/InvenTree/search.html:183 templates/js/barcode.js:363
#: templates/js/barcode.js:531 templates/js/build.js:434
@@ -694,7 +713,7 @@ msgid "Admin view"
msgstr ""
#: build/templates/build/build_base.html:43
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
#: order/templates/order/order_base.html:32
#: order/templates/order/order_base.html:83
#: order/templates/order/sales_order_base.html:41
@@ -704,64 +723,87 @@ msgstr ""
msgid "Overdue"
msgstr ""
-#: build/templates/build/build_base.html:51
+#: build/templates/build/build_base.html:52
+msgid "Print actions"
+msgstr ""
+
+#: build/templates/build/build_base.html:56
+msgid "Print Build Order"
+msgstr ""
+
+#: build/templates/build/build_base.html:62
+msgid "Build actions"
+msgstr ""
+
+#: build/templates/build/build_base.html:66
msgid "Edit Build"
msgstr ""
-#: build/templates/build/build_base.html:55
+#: build/templates/build/build_base.html:68
msgid "Complete Build"
msgstr ""
-#: build/templates/build/build_base.html:58 build/views.py:58
+#: build/templates/build/build_base.html:69 build/views.py:58
msgid "Cancel Build"
msgstr ""
-#: build/templates/build/build_base.html:64
-msgid "Delete Build"
-msgstr ""
-
-#: build/templates/build/build_base.html:74 build/templates/build/detail.html:9
+#: build/templates/build/build_base.html:82 build/templates/build/detail.html:9
msgid "Build Details"
msgstr ""
-#: build/templates/build/build_base.html:88
+#: build/templates/build/build_base.html:96
#: build/templates/build/detail.html:57
#: order/templates/order/receive_parts.html:24
-#: stock/templates/stock/item_base.html:367 templates/InvenTree/search.html:175
-#: templates/js/barcode.js:119 templates/js/build.js:697
+#: stock/templates/stock/item_base.html:363 templates/InvenTree/search.html:175
+#: templates/js/barcode.js:119 templates/js/build.js:703
#: templates/js/order.js:185 templates/js/order.js:279
#: templates/js/stock.js:585 templates/js/stock.js:1157
msgid "Status"
msgstr ""
-#: build/templates/build/build_base.html:96
-#: build/templates/build/detail.html:100
+#: build/templates/build/build_base.html:104
+#: build/templates/build/detail.html:119
#: order/templates/order/order_base.html:121
-#: order/templates/order/sales_order_base.html:114 templates/js/build.js:710
-#: templates/js/order.js:198 templates/js/order.js:292
+#: order/templates/order/sales_order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:128
+#: templates/js/build.js:716 templates/js/order.js:198
+#: templates/js/order.js:292
msgid "Target Date"
msgstr ""
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
msgid "This build was due on"
msgstr ""
-#: build/templates/build/build_base.html:107
+#: build/templates/build/build_base.html:115
#: build/templates/build/detail.html:62
msgid "Progress"
msgstr ""
-#: build/templates/build/build_base.html:120
+#: build/templates/build/build_base.html:128
#: build/templates/build/detail.html:82 order/models.py:650
#: order/templates/order/sales_order_base.html:9
#: order/templates/order/sales_order_base.html:33
#: order/templates/order/sales_order_notes.html:10
#: order/templates/order/sales_order_ship.html:25
#: part/templates/part/allocation.html:27
-#: stock/templates/stock/item_base.html:262 templates/js/order.js:240
+#: report/templates/report/inventree_build_order_base.html:138
+#: stock/templates/stock/item_base.html:258 templates/js/order.js:240
msgid "Sales Order"
msgstr ""
+#: build/templates/build/build_base.html:135
+#: build/templates/build/detail.html:96
+#: report/templates/report/inventree_build_order_base.html:155
+msgid "Issued By"
+msgstr ""
+
+#: build/templates/build/build_base.html:142
+#: build/templates/build/detail.html:103
+#: report/templates/report/inventree_build_order_base.html:161
+msgid "Responsible"
+msgstr ""
+
#: build/templates/build/build_output.html:9 build/templates/build/tabs.html:17
msgid "Build Outputs"
msgstr ""
@@ -859,28 +901,28 @@ msgid "Destination location not specified"
msgstr ""
#: build/templates/build/detail.html:68
-#: stock/templates/stock/item_base.html:286 templates/js/stock.js:593
+#: stock/templates/stock/item_base.html:282 templates/js/stock.js:593
#: templates/js/stock.js:1164 templates/js/table_filters.js:80
#: templates/js/table_filters.js:161
msgid "Batch"
msgstr ""
-#: build/templates/build/detail.html:95
+#: build/templates/build/detail.html:114
#: order/templates/order/order_base.html:108
-#: order/templates/order/sales_order_base.html:108 templates/js/build.js:705
+#: order/templates/order/sales_order_base.html:108 templates/js/build.js:711
msgid "Created"
msgstr ""
-#: build/templates/build/detail.html:106
+#: build/templates/build/detail.html:125
msgid "No target date set"
msgstr ""
-#: build/templates/build/detail.html:111 templates/js/build.js:683
-#: templates/js/build.js:715
+#: build/templates/build/detail.html:130 templates/js/build.js:689
+#: templates/js/build.js:721
msgid "Completed"
msgstr ""
-#: build/templates/build/detail.html:115
+#: build/templates/build/detail.html:134
msgid "Build not complete"
msgstr ""
@@ -888,17 +930,21 @@ msgstr ""
msgid "Alter the quantity of stock allocated to the build output"
msgstr ""
-#: build/templates/build/index.html:27 build/views.py:658
+#: build/templates/build/index.html:28 build/views.py:658
msgid "New Build Order"
msgstr ""
-#: build/templates/build/index.html:30
+#: build/templates/build/index.html:37 build/templates/build/index.html:38
+msgid "Print Build Orders"
+msgstr ""
+
+#: build/templates/build/index.html:43
#: order/templates/order/purchase_orders.html:22
#: order/templates/order/sales_orders.html:22
msgid "Display calendar view"
msgstr ""
-#: build/templates/build/index.html:33
+#: build/templates/build/index.html:46
#: order/templates/order/purchase_orders.html:25
#: order/templates/order/sales_orders.html:25
msgid "Display list view"
@@ -959,7 +1005,7 @@ msgstr ""
msgid "Create Build Output"
msgstr ""
-#: build/views.py:207 stock/models.py:897 stock/views.py:1804
+#: build/views.py:207 stock/models.py:900 stock/views.py:1804
msgid "Serial numbers already exist"
msgstr ""
@@ -1015,77 +1061,77 @@ msgstr ""
msgid "Build output completed"
msgstr ""
-#: build/views.py:703
+#: build/views.py:706
msgid "Created new build"
msgstr ""
-#: build/views.py:724
+#: build/views.py:727
msgid "Edit Build Order Details"
msgstr ""
-#: build/views.py:758
+#: build/views.py:761
msgid "Edited build"
msgstr ""
-#: build/views.py:767
+#: build/views.py:770
msgid "Delete Build Order"
msgstr ""
-#: build/views.py:784
+#: build/views.py:787
msgid "Removed parts from build allocation"
msgstr ""
-#: build/views.py:796
+#: build/views.py:799
msgid "Allocate stock to build output"
msgstr ""
-#: build/views.py:840
+#: build/views.py:843
msgid "Item must be currently in stock"
msgstr ""
-#: build/views.py:846
+#: build/views.py:849
msgid "Stock item is over-allocated"
msgstr ""
-#: build/views.py:847 templates/js/bom.js:220 templates/js/build.js:519
-#: templates/js/build.js:758
+#: build/views.py:850 templates/js/bom.js:220 templates/js/build.js:519
+#: templates/js/build.js:771
msgid "Available"
msgstr ""
-#: build/views.py:849
+#: build/views.py:852
msgid "Stock item must be selected"
msgstr ""
-#: build/views.py:1012
+#: build/views.py:1015
msgid "Edit Stock Allocation"
msgstr ""
-#: build/views.py:1017
+#: build/views.py:1020
msgid "Updated Build Item"
msgstr ""
-#: build/views.py:1046
+#: build/views.py:1049
msgid "Add Build Order Attachment"
msgstr ""
-#: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170
+#: build/views.py:1063 order/views.py:113 order/views.py:166 part/views.py:170
#: stock/views.py:280
msgid "Added attachment"
msgstr ""
-#: build/views.py:1096 order/views.py:193 order/views.py:215
+#: build/views.py:1099 order/views.py:193 order/views.py:215
msgid "Edit Attachment"
msgstr ""
-#: build/views.py:1107 order/views.py:198 order/views.py:220
+#: build/views.py:1110 order/views.py:198 order/views.py:220
msgid "Attachment updated"
msgstr ""
-#: build/views.py:1117 order/views.py:235 order/views.py:250
+#: build/views.py:1120 order/views.py:235 order/views.py:250
msgid "Delete Attachment"
msgstr ""
-#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:338
+#: build/views.py:1126 order/views.py:242 order/views.py:257 stock/views.py:338
msgid "Deleted attachment"
msgstr ""
@@ -1106,250 +1152,282 @@ msgid "Internal company name"
msgstr ""
#: common/models.py:68
-msgid "Default Currency"
+msgid "Base URL"
msgstr ""
#: common/models.py:69
-msgid "Default currency"
+msgid "Base URL for server instance"
msgstr ""
#: common/models.py:75
-msgid "Barcode Support"
+msgid "Default Currency"
msgstr ""
#: common/models.py:76
-msgid "Enable barcode scanner support"
+msgid "Default currency"
msgstr ""
#: common/models.py:82
-msgid "IPN Regex"
+msgid "Barcode Support"
msgstr ""
#: common/models.py:83
+msgid "Enable barcode scanner support"
+msgstr ""
+
+#: common/models.py:89
+msgid "IPN Regex"
+msgstr ""
+
+#: common/models.py:90
msgid "Regular expression pattern for matching Part IPN"
msgstr ""
-#: common/models.py:87
+#: common/models.py:94
msgid "Allow Duplicate IPN"
msgstr ""
-#: common/models.py:88
+#: common/models.py:95
msgid "Allow multiple parts to share the same IPN"
msgstr ""
-#: common/models.py:94
+#: common/models.py:101
msgid "Copy Part BOM Data"
msgstr ""
-#: common/models.py:95
+#: common/models.py:102
msgid "Copy BOM data by default when duplicating a part"
msgstr ""
-#: common/models.py:101
+#: common/models.py:108
msgid "Copy Part Parameter Data"
msgstr ""
-#: common/models.py:102
+#: common/models.py:109
msgid "Copy parameter data by default when duplicating a part"
msgstr ""
-#: common/models.py:108
+#: common/models.py:115
msgid "Copy Part Test Data"
msgstr ""
-#: common/models.py:109
+#: common/models.py:116
msgid "Copy test data by default when duplicating a part"
msgstr ""
-#: common/models.py:115
+#: common/models.py:122
msgid "Copy Category Parameter Templates"
msgstr ""
-#: common/models.py:116
+#: common/models.py:123
msgid "Copy category parameter templates when creating a part"
msgstr ""
-#: common/models.py:122 part/templates/part/detail.html:155
-#: report/models.py:159 stock/forms.py:257 templates/js/table_filters.js:23
+#: common/models.py:129 part/templates/part/detail.html:157
+#: report/models.py:168 stock/forms.py:257 templates/js/table_filters.js:23
#: templates/js/table_filters.js:270
msgid "Template"
msgstr ""
-#: common/models.py:123
+#: common/models.py:130
msgid "Parts are templates by default"
msgstr ""
-#: common/models.py:129 part/models.py:801 part/templates/part/detail.html:165
+#: common/models.py:136 part/models.py:801 part/templates/part/detail.html:167
#: templates/js/table_filters.js:282
msgid "Assembly"
msgstr ""
-#: common/models.py:130
+#: common/models.py:137
msgid "Parts can be assembled from other components by default"
msgstr ""
-#: common/models.py:136 part/models.py:807 part/templates/part/detail.html:175
+#: common/models.py:143 part/models.py:807 part/templates/part/detail.html:177
#: templates/js/table_filters.js:286
msgid "Component"
msgstr ""
-#: common/models.py:137
+#: common/models.py:144
msgid "Parts can be used as sub-components by default"
msgstr ""
-#: common/models.py:143 part/models.py:818 part/templates/part/detail.html:195
+#: common/models.py:150 part/models.py:818 part/templates/part/detail.html:197
msgid "Purchaseable"
msgstr ""
-#: common/models.py:144
+#: common/models.py:151
msgid "Parts are purchaseable by default"
msgstr ""
-#: common/models.py:150 part/models.py:823 part/templates/part/detail.html:205
+#: common/models.py:157 part/models.py:823 part/templates/part/detail.html:207
#: templates/js/table_filters.js:294
msgid "Salable"
msgstr ""
-#: common/models.py:151
+#: common/models.py:158
msgid "Parts are salable by default"
msgstr ""
-#: common/models.py:157 part/models.py:813 part/templates/part/detail.html:185
+#: common/models.py:164 part/models.py:813 part/templates/part/detail.html:187
#: templates/js/table_filters.js:31 templates/js/table_filters.js:298
msgid "Trackable"
msgstr ""
-#: common/models.py:158
+#: common/models.py:165
msgid "Parts are trackable by default"
msgstr ""
-#: common/models.py:164 part/models.py:833 part/templates/part/detail.html:145
+#: common/models.py:171 part/models.py:833 part/templates/part/detail.html:147
#: templates/js/table_filters.js:27
msgid "Virtual"
msgstr ""
-#: common/models.py:165
+#: common/models.py:172
msgid "Parts are virtual by default"
msgstr ""
-#: common/models.py:171
+#: common/models.py:178
msgid "Show Quantity in Forms"
msgstr ""
-#: common/models.py:172
+#: common/models.py:179
msgid "Display available part quantity in some forms"
msgstr ""
-#: common/models.py:178
-msgid "Stock Expiry"
-msgstr ""
-
-#: common/models.py:179
-msgid "Enable stock expiry functionality"
-msgstr ""
-
#: common/models.py:185
-msgid "Sell Expired Stock"
+msgid "Debug Mode"
msgstr ""
#: common/models.py:186
-msgid "Allow sale of expired stock"
+msgid "Generate reports in debug mode (HTML output)"
msgstr ""
#: common/models.py:192
-msgid "Stock Stale Time"
+msgid "Page Size"
msgstr ""
#: common/models.py:193
-msgid "Number of days stock items are considered stale before expiring"
+msgid "Default page size for PDF reports"
msgstr ""
-#: common/models.py:195 part/templates/part/detail.html:116
-msgid "days"
+#: common/models.py:203
+msgid "Test Reports"
msgstr ""
-#: common/models.py:200
-msgid "Build Expired Stock"
+#: common/models.py:204
+msgid "Enable generation of test reports"
msgstr ""
-#: common/models.py:201
-msgid "Allow building with expired stock"
+#: common/models.py:210
+msgid "Stock Expiry"
msgstr ""
-#: common/models.py:207
-msgid "Stock Ownership Control"
+#: common/models.py:211
+msgid "Enable stock expiry functionality"
msgstr ""
-#: common/models.py:208
-msgid "Enable ownership control over stock locations and items"
+#: common/models.py:217
+msgid "Sell Expired Stock"
msgstr ""
-#: common/models.py:214
-msgid "Build Order Reference Prefix"
+#: common/models.py:218
+msgid "Allow sale of expired stock"
msgstr ""
-#: common/models.py:215
-msgid "Prefix value for build order reference"
-msgstr ""
-
-#: common/models.py:220
-msgid "Build Order Reference Regex"
-msgstr ""
-
-#: common/models.py:221
-msgid "Regular expression pattern for matching build order reference"
+#: common/models.py:224
+msgid "Stock Stale Time"
msgstr ""
#: common/models.py:225
-msgid "Sales Order Reference Prefix"
+msgid "Number of days stock items are considered stale before expiring"
msgstr ""
-#: common/models.py:226
-msgid "Prefix value for sales order reference"
-msgstr ""
-
-#: common/models.py:231
-msgid "Purchase Order Reference Prefix"
+#: common/models.py:227 part/templates/part/detail.html:118
+msgid "days"
msgstr ""
#: common/models.py:232
+msgid "Build Expired Stock"
+msgstr ""
+
+#: common/models.py:233
+msgid "Allow building with expired stock"
+msgstr ""
+
+#: common/models.py:239
+msgid "Stock Ownership Control"
+msgstr ""
+
+#: common/models.py:240
+msgid "Enable ownership control over stock locations and items"
+msgstr ""
+
+#: common/models.py:246
+msgid "Build Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:247
+msgid "Prefix value for build order reference"
+msgstr ""
+
+#: common/models.py:252
+msgid "Build Order Reference Regex"
+msgstr ""
+
+#: common/models.py:253
+msgid "Regular expression pattern for matching build order reference"
+msgstr ""
+
+#: common/models.py:257
+msgid "Sales Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:258
+msgid "Prefix value for sales order reference"
+msgstr ""
+
+#: common/models.py:263
+msgid "Purchase Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:264
msgid "Prefix value for purchase order reference"
msgstr ""
-#: common/models.py:455
+#: common/models.py:487
msgid "Settings key (must be unique - case insensitive"
msgstr ""
-#: common/models.py:457
+#: common/models.py:489
msgid "Settings value"
msgstr ""
-#: common/models.py:514
+#: common/models.py:551
msgid "Value must be a boolean value"
msgstr ""
-#: common/models.py:524
+#: common/models.py:561
msgid "Value must be an integer value"
msgstr ""
-#: common/models.py:538
+#: common/models.py:575
msgid "Key string must be unique"
msgstr ""
-#: common/models.py:611 company/forms.py:113
+#: common/models.py:648 company/forms.py:113
msgid "Price break quantity"
msgstr ""
-#: common/models.py:619 company/templates/company/supplier_part_pricing.html:80
+#: common/models.py:656 company/templates/company/supplier_part_pricing.html:80
#: part/templates/part/sale_prices.html:87 templates/js/bom.js:245
msgid "Price"
msgstr ""
-#: common/models.py:620
+#: common/models.py:657
msgid "Unit price at specified quantity"
msgstr ""
-#: common/models.py:643
+#: common/models.py:680
msgid "Default"
msgstr ""
@@ -1450,8 +1528,8 @@ msgstr ""
msgid "Currency"
msgstr ""
-#: company/models.py:313 stock/models.py:366
-#: stock/templates/stock/item_base.html:218
+#: company/models.py:313 stock/models.py:369
+#: stock/templates/stock/item_base.html:214
msgid "Base Part"
msgstr ""
@@ -1464,7 +1542,7 @@ msgstr ""
#: company/templates/company/supplier_part_detail.html:21
#: order/templates/order/order_base.html:89
#: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170
-#: stock/templates/stock/item_base.html:328 templates/js/company.js:48
+#: stock/templates/stock/item_base.html:324 templates/js/company.js:48
#: templates/js/company.js:164 templates/js/order.js:167
msgid "Supplier"
msgstr ""
@@ -1503,8 +1581,9 @@ msgstr ""
msgid "Manufacturer part number"
msgstr ""
-#: company/models.py:353 part/models.py:711 templates/js/company.js:208
-#: templates/js/part.js:451
+#: company/models.py:353 part/models.py:711
+#: report/templates/report/inventree_build_order_base.html:167
+#: templates/js/company.js:208 templates/js/part.js:451
msgid "Link"
msgstr ""
@@ -1561,8 +1640,8 @@ msgid "Uses default currency"
msgstr ""
#: company/templates/company/detail.html:62
-#: order/templates/order/sales_order_base.html:89 stock/models.py:401
-#: stock/models.py:402 stock/templates/stock/item_base.html:245
+#: order/templates/order/sales_order_base.html:89 stock/models.py:404
+#: stock/models.py:405 stock/templates/stock/item_base.html:241
#: templates/js/company.js:40 templates/js/order.js:261
msgid "Customer"
msgstr ""
@@ -1601,7 +1680,7 @@ msgid "Delete Parts"
msgstr ""
#: company/templates/company/detail_part.html:63
-#: part/templates/part/bom.html:182 part/templates/part/category.html:116
+#: part/templates/part/bom.html:185 part/templates/part/category.html:116
#: templates/js/stock.js:1035
msgid "New Part"
msgstr ""
@@ -1634,8 +1713,8 @@ msgstr ""
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
-#: part/templates/part/bom.html:63 part/templates/part/category.html:112
-#: part/templates/part/category.html:126 part/templates/part/stock.html:51
+#: part/templates/part/category.html:112 part/templates/part/category.html:126
+#: part/templates/part/stock.html:51
msgid "Export"
msgstr ""
@@ -1657,7 +1736,7 @@ msgstr ""
#: order/templates/order/purchase_orders.html:8
#: order/templates/order/purchase_orders.html:13
#: part/templates/part/orders.html:9 part/templates/part/tabs.html:48
-#: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33
+#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:37
#: users/models.py:37
msgid "Purchase Orders"
msgstr ""
@@ -1677,7 +1756,7 @@ msgstr ""
#: order/templates/order/sales_orders.html:8
#: order/templates/order/sales_orders.html:13
#: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56
-#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42
+#: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:46
#: users/models.py:38
msgid "Sales Orders"
msgstr ""
@@ -1693,13 +1772,13 @@ msgid "New Sales Order"
msgstr ""
#: company/templates/company/supplier_part_base.html:6
-#: company/templates/company/supplier_part_base.html:19 stock/models.py:375
-#: stock/templates/stock/item_base.html:333 templates/js/company.js:180
+#: company/templates/company/supplier_part_base.html:19 stock/models.py:378
+#: stock/templates/stock/item_base.html:329 templates/js/company.js:180
msgid "Supplier Part"
msgstr ""
#: company/templates/company/supplier_part_base.html:26
-#: part/templates/part/orders.html:14 part/templates/part/part_base.html:69
+#: part/templates/part/orders.html:14 part/templates/part/part_base.html:68
msgid "Order part"
msgstr ""
@@ -1765,8 +1844,8 @@ msgstr ""
#: company/templates/company/supplier_part_tabs.html:8
#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18
#: stock/templates/stock/location.html:29 templates/InvenTree/search.html:155
-#: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192
-#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:22
+#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:192
+#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:26
msgid "Stock"
msgstr ""
@@ -1778,21 +1857,21 @@ msgstr ""
#: order/templates/order/receive_parts.html:14 part/models.py:321
#: part/templates/part/cat_link.html:7 part/templates/part/category.html:94
#: part/templates/part/category_tabs.html:6
-#: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19
+#: templates/InvenTree/settings/tabs.html:25 templates/navbar.html:23
#: templates/stats.html:35 templates/stats.html:44 users/models.py:33
msgid "Parts"
msgstr ""
#: company/views.py:55 part/templates/part/tabs.html:42
-#: templates/navbar.html:31
+#: templates/navbar.html:35
msgid "Suppliers"
msgstr ""
-#: company/views.py:62 templates/navbar.html:32
+#: company/views.py:62 templates/navbar.html:36
msgid "Manufacturers"
msgstr ""
-#: company/views.py:69 templates/navbar.html:41
+#: company/views.py:69 templates/navbar.html:45
msgid "Customers"
msgstr ""
@@ -1868,47 +1947,47 @@ msgstr ""
msgid "Delete Price Break"
msgstr ""
-#: label/api.py:171 report/api.py:161
+#: label/api.py:179
msgid "Must provide valid StockItem(s)"
msgstr ""
-#: label/api.py:185 label/api.py:337
+#: label/api.py:193 label/api.py:353
msgid "Error during label rendering"
msgstr ""
-#: label/api.py:324
+#: label/api.py:340
msgid "Must provide valid StockLocation(s)"
msgstr ""
-#: label/models.py:69
+#: label/models.py:70
msgid "Label name"
msgstr ""
-#: label/models.py:76
+#: label/models.py:77
msgid "Label description"
msgstr ""
-#: label/models.py:83 stock/forms.py:200
+#: label/models.py:84 stock/forms.py:200
msgid "Label"
msgstr ""
-#: label/models.py:84
+#: label/models.py:85
msgid "Label template file"
msgstr ""
-#: label/models.py:90 report/models.py:172
+#: label/models.py:91 report/models.py:257
msgid "Enabled"
msgstr ""
-#: label/models.py:91
+#: label/models.py:92
msgid "Label template is enabled"
msgstr ""
-#: label/models.py:137 label/models.py:190
+#: label/models.py:138 label/models.py:194
msgid "Query filters (comma-separated list of key=value pairs"
msgstr ""
-#: label/models.py:138 label/models.py:191 report/models.py:194
+#: label/models.py:139 label/models.py:195 report/models.py:277
msgid "Filters"
msgstr ""
@@ -2004,7 +2083,7 @@ msgid "Date order was completed"
msgstr ""
#: order/models.py:230 order/models.py:329 part/views.py:1506
-#: stock/models.py:265 stock/models.py:881
+#: stock/models.py:268 stock/models.py:884
msgid "Quantity must be greater than zero"
msgstr ""
@@ -2016,6 +2095,10 @@ msgstr ""
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr ""
+#: order/models.py:346
+msgid "Received items"
+msgstr ""
+
#: order/models.py:427
msgid "Company to which the items are being sold"
msgstr ""
@@ -2042,7 +2125,7 @@ msgstr ""
#: order/models.py:608 order/templates/order/order_base.html:9
#: order/templates/order/order_base.html:24
-#: stock/templates/stock/item_base.html:300 templates/js/order.js:145
+#: stock/templates/stock/item_base.html:296 templates/js/order.js:145
msgid "Purchase Order"
msgstr ""
@@ -2054,8 +2137,8 @@ msgstr ""
msgid "Number of items received"
msgstr ""
-#: order/models.py:631 stock/models.py:494
-#: stock/templates/stock/item_base.html:307
+#: order/models.py:631 stock/models.py:497
+#: stock/templates/stock/item_base.html:303
msgid "Purchase Price"
msgstr ""
@@ -2124,6 +2207,7 @@ msgid "Supplier Reference"
msgstr ""
#: order/templates/order/order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:124
msgid "Issued"
msgstr ""
@@ -2258,7 +2342,7 @@ msgid "Select parts to receive against this order"
msgstr ""
#: order/templates/order/receive_parts.html:21
-#: part/templates/part/part_base.html:148 templates/js/part.js:434
+#: part/templates/part/part_base.html:147 templates/js/part.js:434
msgid "On Order"
msgstr ""
@@ -2298,24 +2382,26 @@ msgid "Sales Order Items"
msgstr ""
#: order/templates/order/sales_order_detail.html:72
-#: order/templates/order/sales_order_detail.html:154 stock/models.py:406
-#: stock/templates/stock/item_base.html:232 templates/js/build.js:418
+#: order/templates/order/sales_order_detail.html:154
+#: report/templates/report/inventree_test_report_base.html:75
+#: stock/models.py:409 stock/templates/stock/item_base.html:228
+#: templates/js/build.js:418
msgid "Serial Number"
msgstr ""
#: order/templates/order/sales_order_detail.html:96 templates/js/build.js:459
-#: templates/js/build.js:769
+#: templates/js/build.js:782
msgid "Edit stock allocation"
msgstr ""
#: order/templates/order/sales_order_detail.html:97 templates/js/build.js:461
-#: templates/js/build.js:770
+#: templates/js/build.js:783
msgid "Delete stock allocation"
msgstr ""
#: order/templates/order/sales_order_detail.html:225
#: part/templates/part/tabs.html:23 templates/js/build.js:523
-#: templates/js/build.js:765
+#: templates/js/build.js:778
msgid "Allocated"
msgstr ""
@@ -2514,7 +2600,7 @@ msgstr ""
msgid "Default Location"
msgstr ""
-#: part/bom.py:139 part/templates/part/part_base.html:121
+#: part/bom.py:139 part/templates/part/part_base.html:120
msgid "Available Stock"
msgstr ""
@@ -2738,7 +2824,7 @@ msgid "Part category"
msgstr ""
#: part/models.py:698 part/templates/part/detail.html:25
-#: part/templates/part/part_base.html:98 templates/js/part.js:180
+#: part/templates/part/part_base.html:97 templates/js/part.js:180
msgid "IPN"
msgstr ""
@@ -2750,7 +2836,7 @@ msgstr ""
msgid "Part revision or version number"
msgstr ""
-#: part/models.py:706 part/templates/part/detail.html:32
+#: part/models.py:706 part/templates/part/detail.html:32 report/models.py:181
#: templates/js/part.js:184
msgid "Revision"
msgstr ""
@@ -2775,7 +2861,7 @@ msgstr ""
msgid "Expiry time (in days) for stock items of this part"
msgstr ""
-#: part/models.py:788 part/templates/part/detail.html:108
+#: part/models.py:788 part/templates/part/detail.html:110
msgid "Minimum Stock"
msgstr ""
@@ -2783,7 +2869,7 @@ msgstr ""
msgid "Minimum allowed stock level"
msgstr ""
-#: part/models.py:795 part/templates/part/detail.html:102
+#: part/models.py:795 part/templates/part/detail.html:103
#: part/templates/part/params.html:26
msgid "Units"
msgstr ""
@@ -2812,7 +2898,7 @@ msgstr ""
msgid "Can this part be sold to customers?"
msgstr ""
-#: part/models.py:828 part/templates/part/detail.html:222
+#: part/models.py:828 part/templates/part/detail.html:224
#: templates/js/table_filters.js:19 templates/js/table_filters.js:55
#: templates/js/table_filters.js:196 templates/js/table_filters.js:265
msgid "Active"
@@ -2941,7 +3027,7 @@ msgid "BOM line checksum"
msgstr ""
#: part/models.py:1967 part/views.py:1512 part/views.py:1564
-#: stock/models.py:255
+#: stock/models.py:258
msgid "Quantity must be integer value for trackable parts"
msgstr ""
@@ -2978,8 +3064,8 @@ msgstr ""
#: part/templates/part/allocation.html:45
#: stock/templates/stock/item_base.html:8
#: stock/templates/stock/item_base.html:89
-#: stock/templates/stock/item_base.html:315
-#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751
+#: stock/templates/stock/item_base.html:311
+#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:764
#: templates/js/stock.js:880 templates/js/stock.js:1140
msgid "Stock Item"
msgstr ""
@@ -3008,64 +3094,43 @@ msgstr ""
msgid "Import BOM data"
msgstr ""
-#: part/templates/part/bom.html:38
-msgid "Import from File"
-msgstr ""
-
#: part/templates/part/bom.html:41
msgid "Copy BOM from parent part"
msgstr ""
-#: part/templates/part/bom.html:42
-msgid "Copy from Parent"
-msgstr ""
-
#: part/templates/part/bom.html:45
msgid "New BOM Item"
msgstr ""
-#: part/templates/part/bom.html:46
-msgid "Add Item"
-msgstr ""
-
#: part/templates/part/bom.html:48
msgid "Finish Editing"
msgstr ""
-#: part/templates/part/bom.html:49
-msgid "Finished"
-msgstr ""
-
#: part/templates/part/bom.html:53
msgid "Edit BOM"
msgstr ""
-#: part/templates/part/bom.html:54 part/templates/part/params.html:38
-#: templates/InvenTree/settings/user.html:19
-msgid "Edit"
-msgstr ""
-
#: part/templates/part/bom.html:57
msgid "Validate Bill of Materials"
msgstr ""
-#: part/templates/part/bom.html:58
-msgid "Validate"
-msgstr ""
-
-#: part/templates/part/bom.html:62 part/views.py:1803
+#: part/templates/part/bom.html:63 part/views.py:1803
msgid "Export Bill of Materials"
msgstr ""
-#: part/templates/part/bom.html:123
+#: part/templates/part/bom.html:66
+msgid "Print BOM Report"
+msgstr ""
+
+#: part/templates/part/bom.html:126
msgid "Delete selected BOM items?"
msgstr ""
-#: part/templates/part/bom.html:124
+#: part/templates/part/bom.html:127
msgid "All selected BOM items will be deleted"
msgstr ""
-#: part/templates/part/bom.html:183 part/views.py:594
+#: part/templates/part/bom.html:186 part/views.py:594
#: templates/js/stock.js:1036
msgid "Create New Part"
msgstr ""
@@ -3265,79 +3330,79 @@ msgstr ""
msgid "No serial numbers recorded"
msgstr ""
-#: part/templates/part/detail.html:115
+#: part/templates/part/detail.html:117
msgid "Stock Expiry Time"
msgstr ""
-#: part/templates/part/detail.html:121 templates/js/order.js:287
+#: part/templates/part/detail.html:123 templates/js/order.js:287
msgid "Creation Date"
msgstr ""
-#: part/templates/part/detail.html:127
+#: part/templates/part/detail.html:129
msgid "Created By"
msgstr ""
-#: part/templates/part/detail.html:134
+#: part/templates/part/detail.html:136
msgid "Responsible User"
msgstr ""
-#: part/templates/part/detail.html:148
+#: part/templates/part/detail.html:150
msgid "Part is virtual (not a physical part)"
msgstr ""
-#: part/templates/part/detail.html:150
+#: part/templates/part/detail.html:152
msgid "Part is not a virtual part"
msgstr ""
-#: part/templates/part/detail.html:158
+#: part/templates/part/detail.html:160
msgid "Part is a template part (variants can be made from this part)"
msgstr ""
-#: part/templates/part/detail.html:160
+#: part/templates/part/detail.html:162
msgid "Part is not a template part"
msgstr ""
-#: part/templates/part/detail.html:168
+#: part/templates/part/detail.html:170
msgid "Part can be assembled from other parts"
msgstr ""
-#: part/templates/part/detail.html:170
+#: part/templates/part/detail.html:172
msgid "Part cannot be assembled from other parts"
msgstr ""
-#: part/templates/part/detail.html:178
+#: part/templates/part/detail.html:180
msgid "Part can be used in assemblies"
msgstr ""
-#: part/templates/part/detail.html:180
+#: part/templates/part/detail.html:182
msgid "Part cannot be used in assemblies"
msgstr ""
-#: part/templates/part/detail.html:188
+#: part/templates/part/detail.html:190
msgid "Part stock is tracked by serial number"
msgstr ""
-#: part/templates/part/detail.html:190
+#: part/templates/part/detail.html:192
msgid "Part stock is not tracked by serial number"
msgstr ""
-#: part/templates/part/detail.html:198 part/templates/part/detail.html:200
+#: part/templates/part/detail.html:200 part/templates/part/detail.html:202
msgid "Part can be purchased from external suppliers"
msgstr ""
-#: part/templates/part/detail.html:208
+#: part/templates/part/detail.html:210
msgid "Part can be sold to customers"
msgstr ""
-#: part/templates/part/detail.html:210
+#: part/templates/part/detail.html:212
msgid "Part cannot be sold to customers"
msgstr ""
-#: part/templates/part/detail.html:225
+#: part/templates/part/detail.html:227
msgid "Part is active"
msgstr ""
-#: part/templates/part/detail.html:227
+#: part/templates/part/detail.html:229
msgid "Part is not active"
msgstr ""
@@ -3359,13 +3424,19 @@ msgstr ""
msgid "New Parameter"
msgstr ""
-#: part/templates/part/params.html:25 stock/models.py:1541
-#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:124
+#: part/templates/part/params.html:25
+#: report/templates/report/inventree_test_report_base.html:90
+#: stock/models.py:1569 templates/InvenTree/settings/header.html:8
+#: templates/js/stock.js:124
msgid "Value"
msgstr ""
+#: part/templates/part/params.html:38 templates/InvenTree/settings/user.html:19
+msgid "Edit"
+msgstr ""
+
#: part/templates/part/params.html:41 part/templates/part/related.html:41
-#: part/templates/part/supplier.html:19 users/models.py:164
+#: part/templates/part/supplier.html:19 users/models.py:167
msgid "Delete"
msgstr ""
@@ -3394,65 +3465,65 @@ msgstr ""
msgid "Star this part"
msgstr ""
-#: part/templates/part/part_base.html:51
+#: part/templates/part/part_base.html:50
#: stock/templates/stock/item_base.html:127
-#: stock/templates/stock/location.html:45
+#: stock/templates/stock/location.html:44
msgid "Barcode actions"
msgstr ""
-#: part/templates/part/part_base.html:53
+#: part/templates/part/part_base.html:52
#: stock/templates/stock/item_base.html:129
-#: stock/templates/stock/location.html:47
+#: stock/templates/stock/location.html:46
msgid "Show QR Code"
msgstr ""
-#: part/templates/part/part_base.html:54
-#: stock/templates/stock/item_base.html:147
-#: stock/templates/stock/location.html:48
+#: part/templates/part/part_base.html:53
+#: stock/templates/stock/item_base.html:145
+#: stock/templates/stock/location.html:47
msgid "Print Label"
msgstr ""
-#: part/templates/part/part_base.html:59
+#: part/templates/part/part_base.html:58
msgid "Show pricing information"
msgstr ""
-#: part/templates/part/part_base.html:63
+#: part/templates/part/part_base.html:62
msgid "Count part stock"
msgstr ""
-#: part/templates/part/part_base.html:78
+#: part/templates/part/part_base.html:77
msgid "Part actions"
msgstr ""
-#: part/templates/part/part_base.html:81
+#: part/templates/part/part_base.html:80
msgid "Duplicate part"
msgstr ""
-#: part/templates/part/part_base.html:84
+#: part/templates/part/part_base.html:83
msgid "Edit part"
msgstr ""
-#: part/templates/part/part_base.html:87
+#: part/templates/part/part_base.html:86
msgid "Delete part"
msgstr ""
-#: part/templates/part/part_base.html:127 templates/js/table_filters.js:121
+#: part/templates/part/part_base.html:126 templates/js/table_filters.js:121
msgid "In Stock"
msgstr ""
-#: part/templates/part/part_base.html:134
+#: part/templates/part/part_base.html:133
msgid "Allocated to Build Orders"
msgstr ""
-#: part/templates/part/part_base.html:141
+#: part/templates/part/part_base.html:140
msgid "Allocated to Sales Orders"
msgstr ""
-#: part/templates/part/part_base.html:163 templates/js/bom.js:260
+#: part/templates/part/part_base.html:162 templates/js/bom.js:260
msgid "Can Build"
msgstr ""
-#: part/templates/part/part_base.html:169
+#: part/templates/part/part_base.html:168
msgid "Underway"
msgstr ""
@@ -3545,7 +3616,7 @@ msgstr ""
msgid "Used In"
msgstr ""
-#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:373
+#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:369
msgid "Tests"
msgstr ""
@@ -3794,34 +3865,101 @@ msgstr ""
msgid "Confim BOM item deletion"
msgstr ""
-#: report/models.py:153
+#: report/api.py:151
+msgid "No valid objects provided to template"
+msgstr ""
+
+#: report/models.py:163
msgid "Template name"
msgstr ""
-#: report/models.py:160
+#: report/models.py:169
msgid "Report template file"
msgstr ""
-#: report/models.py:167
+#: report/models.py:176
msgid "Report template description"
msgstr ""
-#: report/models.py:173
+#: report/models.py:182
+msgid "Report revision number (auto-increments)"
+msgstr ""
+
+#: report/models.py:258
msgid "Report template is enabled"
msgstr ""
-#: report/models.py:195
-msgid "Part query filters (comma-separated list of key=value pairs)"
+#: report/models.py:278
+msgid "StockItem query filters (comma-separated list of key=value pairs)"
msgstr ""
-#: report/models.py:244
+#: report/models.py:324
+msgid "Build Filters"
+msgstr ""
+
+#: report/models.py:325
+msgid "Build query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:361
+msgid "Part Filters"
+msgstr ""
+
+#: report/models.py:362
+msgid "Part query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:407
+msgid "Report snippet file"
+msgstr ""
+
+#: report/models.py:411
+msgid "Snippet file description"
+msgstr ""
+
+#: report/models.py:446
msgid "Report asset file"
msgstr ""
-#: report/models.py:247
+#: report/models.py:449
msgid "Asset file description"
msgstr ""
+#: report/templates/report/inventree_build_order_base.html:149
+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:83
+msgid "Test Results"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:88
+#: stock/models.py:1557
+msgid "Test"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:89
+#: stock/models.py:1563
+msgid "Result"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:92
+#: templates/js/order.js:193 templates/js/stock.js:862
+msgid "Date"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:103
+msgid "Pass"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:105
+msgid "Fail"
+msgstr ""
+
#: stock/forms.py:117
msgid "Enter unique serial numbers (or leave blank)"
msgstr ""
@@ -3886,237 +4024,233 @@ msgstr ""
msgid "Set the destination as the default location for selected parts"
msgstr ""
-#: stock/models.py:200
+#: stock/models.py:203
msgid "Created stock item"
msgstr ""
-#: stock/models.py:236
+#: stock/models.py:239
msgid "StockItem with this serial number already exists"
msgstr ""
-#: stock/models.py:272
+#: stock/models.py:275
#, python-brace-format
msgid "Part type ('{pf}') must be {pe}"
msgstr ""
-#: stock/models.py:282 stock/models.py:291
+#: stock/models.py:285 stock/models.py:294
msgid "Quantity must be 1 for item with a serial number"
msgstr ""
-#: stock/models.py:283
+#: stock/models.py:286
msgid "Serial number cannot be set if quantity greater than 1"
msgstr ""
-#: stock/models.py:305
+#: stock/models.py:308
msgid "Item cannot belong to itself"
msgstr ""
-#: stock/models.py:311
+#: stock/models.py:314
msgid "Item must have a build reference if is_building=True"
msgstr ""
-#: stock/models.py:318
+#: stock/models.py:321
msgid "Build reference does not point to the same part object"
msgstr ""
-#: stock/models.py:358
+#: stock/models.py:361
msgid "Parent Stock Item"
msgstr ""
-#: stock/models.py:367
+#: stock/models.py:370
msgid "Base part"
msgstr ""
-#: stock/models.py:376
+#: stock/models.py:379
msgid "Select a matching supplier part for this stock item"
msgstr ""
-#: stock/models.py:381 stock/templates/stock/stock_app_base.html:7
+#: stock/models.py:384 stock/templates/stock/stock_app_base.html:7
msgid "Stock Location"
msgstr ""
-#: stock/models.py:384
+#: stock/models.py:387
msgid "Where is this stock item located?"
msgstr ""
-#: stock/models.py:389 stock/templates/stock/item_base.html:253
+#: stock/models.py:392 stock/templates/stock/item_base.html:249
msgid "Installed In"
msgstr ""
-#: stock/models.py:392
+#: stock/models.py:395
msgid "Is this item installed in another item?"
msgstr ""
-#: stock/models.py:408
+#: stock/models.py:411
msgid "Serial number for this item"
msgstr ""
-#: stock/models.py:420
+#: stock/models.py:423
msgid "Batch code for this stock item"
msgstr ""
-#: stock/models.py:424
+#: stock/models.py:427
msgid "Stock Quantity"
msgstr ""
-#: stock/models.py:433
+#: stock/models.py:436
msgid "Source Build"
msgstr ""
-#: stock/models.py:435
+#: stock/models.py:438
msgid "Build for this stock item"
msgstr ""
-#: stock/models.py:446
+#: stock/models.py:449
msgid "Source Purchase Order"
msgstr ""
-#: stock/models.py:449
+#: stock/models.py:452
msgid "Purchase order for this stock item"
msgstr ""
-#: stock/models.py:455
+#: stock/models.py:458
msgid "Destination Sales Order"
msgstr ""
-#: stock/models.py:461 stock/templates/stock/item_base.html:340
+#: stock/models.py:464 stock/templates/stock/item_base.html:336
#: templates/js/stock.js:613
msgid "Expiry Date"
msgstr ""
-#: stock/models.py:462
+#: stock/models.py:465
msgid ""
"Expiry date for stock item. Stock will be considered expired after this date"
msgstr ""
-#: stock/models.py:475
+#: stock/models.py:478
msgid "Delete this Stock Item when stock is depleted"
msgstr ""
-#: stock/models.py:485 stock/templates/stock/item_notes.html:14
+#: stock/models.py:488 stock/templates/stock/item_notes.html:14
#: stock/templates/stock/item_notes.html:30
msgid "Stock Item Notes"
msgstr ""
-#: stock/models.py:495
+#: stock/models.py:498
msgid "Single unit purchase price at time of purchase"
msgstr ""
-#: stock/models.py:599
+#: stock/models.py:602
msgid "Assigned to Customer"
msgstr ""
-#: stock/models.py:601
+#: stock/models.py:604
msgid "Manually assigned to customer"
msgstr ""
-#: stock/models.py:614
+#: stock/models.py:617
msgid "Returned from customer"
msgstr ""
-#: stock/models.py:616
+#: stock/models.py:619
msgid "Returned to location"
msgstr ""
-#: stock/models.py:741
+#: stock/models.py:744
msgid "Installed into stock item"
msgstr ""
-#: stock/models.py:749
+#: stock/models.py:752
msgid "Installed stock item"
msgstr ""
-#: stock/models.py:773
+#: stock/models.py:776
msgid "Uninstalled stock item"
msgstr ""
-#: stock/models.py:792
+#: stock/models.py:795
msgid "Uninstalled into location"
msgstr ""
-#: stock/models.py:872
+#: stock/models.py:875
msgid "Part is not set as trackable"
msgstr ""
-#: stock/models.py:878
+#: stock/models.py:881
msgid "Quantity must be integer"
msgstr ""
-#: stock/models.py:884
+#: stock/models.py:887
#, python-brace-format
msgid "Quantity must not exceed available stock quantity ({n})"
msgstr ""
-#: stock/models.py:887
+#: stock/models.py:890
msgid "Serial numbers must be a list of integers"
msgstr ""
-#: stock/models.py:890
+#: stock/models.py:893
msgid "Quantity does not match serial numbers"
msgstr ""
-#: stock/models.py:922
+#: stock/models.py:925
msgid "Add serial number"
msgstr ""
-#: stock/models.py:925
+#: stock/models.py:928
#, python-brace-format
msgid "Serialized {n} items"
msgstr ""
-#: stock/models.py:1036
+#: stock/models.py:1006
+msgid "Split from existing stock"
+msgstr ""
+
+#: stock/models.py:1044
msgid "StockItem cannot be moved as it is not in stock"
msgstr ""
-#: stock/models.py:1442
+#: stock/models.py:1470
msgid "Tracking entry title"
msgstr ""
-#: stock/models.py:1444
+#: stock/models.py:1472
msgid "Entry notes"
msgstr ""
-#: stock/models.py:1446
+#: stock/models.py:1474
msgid "Link to external page for further information"
msgstr ""
-#: stock/models.py:1506
+#: stock/models.py:1534
msgid "Value must be provided for this test"
msgstr ""
-#: stock/models.py:1512
+#: stock/models.py:1540
msgid "Attachment must be uploaded for this test"
msgstr ""
-#: stock/models.py:1529
-msgid "Test"
-msgstr ""
-
-#: stock/models.py:1530
+#: stock/models.py:1558
msgid "Test name"
msgstr ""
-#: stock/models.py:1535
-msgid "Result"
-msgstr ""
-
-#: stock/models.py:1536 templates/js/table_filters.js:172
+#: stock/models.py:1564 templates/js/table_filters.js:172
msgid "Test result"
msgstr ""
-#: stock/models.py:1542
+#: stock/models.py:1570
msgid "Test output value"
msgstr ""
-#: stock/models.py:1548
+#: stock/models.py:1576
msgid "Attachment"
msgstr ""
-#: stock/models.py:1549
+#: stock/models.py:1577
msgid "Test result attachment"
msgstr ""
-#: stock/models.py:1555
+#: stock/models.py:1583
msgid "Test notes"
msgstr ""
@@ -4174,12 +4308,12 @@ msgid ""
msgstr ""
#: stock/templates/stock/item_base.html:91
-#: stock/templates/stock/item_base.html:344 templates/js/table_filters.js:111
+#: stock/templates/stock/item_base.html:340 templates/js/table_filters.js:111
msgid "Expired"
msgstr ""
#: stock/templates/stock/item_base.html:95
-#: stock/templates/stock/item_base.html:346 templates/js/table_filters.js:116
+#: stock/templates/stock/item_base.html:342 templates/js/table_filters.js:116
msgid "Stale"
msgstr ""
@@ -4196,115 +4330,115 @@ msgstr ""
msgid "Scan to Location"
msgstr ""
-#: stock/templates/stock/item_base.html:144
+#: stock/templates/stock/item_base.html:143
msgid "Printing actions"
msgstr ""
-#: stock/templates/stock/item_base.html:150
+#: stock/templates/stock/item_base.html:147
#: stock/templates/stock/item_tests.html:25
msgid "Test Report"
msgstr ""
-#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/item_base.html:156
msgid "Stock adjustment actions"
msgstr ""
-#: stock/templates/stock/item_base.html:164
-#: stock/templates/stock/location.html:60 templates/stock_table.html:53
+#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/location.html:59 templates/stock_table.html:55
msgid "Count stock"
msgstr ""
-#: stock/templates/stock/item_base.html:165 templates/stock_table.html:51
+#: stock/templates/stock/item_base.html:161 templates/stock_table.html:53
msgid "Add stock"
msgstr ""
-#: stock/templates/stock/item_base.html:166 templates/stock_table.html:52
+#: stock/templates/stock/item_base.html:162 templates/stock_table.html:54
msgid "Remove stock"
msgstr ""
-#: stock/templates/stock/item_base.html:168
+#: stock/templates/stock/item_base.html:164
msgid "Transfer stock"
msgstr ""
-#: stock/templates/stock/item_base.html:170
+#: stock/templates/stock/item_base.html:166
msgid "Serialize stock"
msgstr ""
-#: stock/templates/stock/item_base.html:174
+#: stock/templates/stock/item_base.html:170
msgid "Assign to customer"
msgstr ""
-#: stock/templates/stock/item_base.html:177
+#: stock/templates/stock/item_base.html:173
msgid "Return to stock"
msgstr ""
-#: stock/templates/stock/item_base.html:181 templates/js/stock.js:1177
+#: stock/templates/stock/item_base.html:177 templates/js/stock.js:1177
msgid "Uninstall stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:181
+#: stock/templates/stock/item_base.html:177
msgid "Uninstall"
msgstr ""
-#: stock/templates/stock/item_base.html:190
-#: stock/templates/stock/location.html:57
+#: stock/templates/stock/item_base.html:186
+#: stock/templates/stock/location.html:56
msgid "Stock actions"
msgstr ""
-#: stock/templates/stock/item_base.html:193
+#: stock/templates/stock/item_base.html:189
msgid "Convert to variant"
msgstr ""
-#: stock/templates/stock/item_base.html:196
+#: stock/templates/stock/item_base.html:192
msgid "Duplicate stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:198
+#: stock/templates/stock/item_base.html:194
msgid "Edit stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:201
+#: stock/templates/stock/item_base.html:197
msgid "Delete stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:213
+#: stock/templates/stock/item_base.html:209
msgid "Stock Item Details"
msgstr ""
-#: stock/templates/stock/item_base.html:272 templates/js/build.js:442
+#: stock/templates/stock/item_base.html:268 templates/js/build.js:442
msgid "No location set"
msgstr ""
-#: stock/templates/stock/item_base.html:279
+#: stock/templates/stock/item_base.html:275
msgid "Barcode Identifier"
msgstr ""
-#: stock/templates/stock/item_base.html:293 templates/js/build.js:642
-#: templates/navbar.html:25
+#: stock/templates/stock/item_base.html:289 templates/js/build.js:648
+#: templates/navbar.html:29
msgid "Build"
msgstr ""
-#: stock/templates/stock/item_base.html:314
+#: stock/templates/stock/item_base.html:310
msgid "Parent Item"
msgstr ""
-#: stock/templates/stock/item_base.html:344
+#: stock/templates/stock/item_base.html:340
msgid "This StockItem expired on"
msgstr ""
-#: stock/templates/stock/item_base.html:346
+#: stock/templates/stock/item_base.html:342
msgid "This StockItem expires on"
msgstr ""
-#: stock/templates/stock/item_base.html:353 templates/js/stock.js:619
+#: stock/templates/stock/item_base.html:349 templates/js/stock.js:619
msgid "Last Updated"
msgstr ""
-#: stock/templates/stock/item_base.html:358
+#: stock/templates/stock/item_base.html:354
msgid "Last Stocktake"
msgstr ""
-#: stock/templates/stock/item_base.html:362
+#: stock/templates/stock/item_base.html:358
msgid "No stocktake performed"
msgstr ""
@@ -4370,50 +4504,50 @@ msgstr ""
msgid "All stock items"
msgstr ""
-#: stock/templates/stock/location.html:49
+#: stock/templates/stock/location.html:48
msgid "Check-in Items"
msgstr ""
-#: stock/templates/stock/location.html:66
+#: stock/templates/stock/location.html:65
msgid "Location actions"
msgstr ""
-#: stock/templates/stock/location.html:68
+#: stock/templates/stock/location.html:67
msgid "Edit location"
msgstr ""
-#: stock/templates/stock/location.html:70
+#: stock/templates/stock/location.html:69
msgid "Delete location"
msgstr ""
-#: stock/templates/stock/location.html:81
+#: stock/templates/stock/location.html:80
msgid "Location Details"
msgstr ""
-#: stock/templates/stock/location.html:86
+#: stock/templates/stock/location.html:85
msgid "Location Path"
msgstr ""
-#: stock/templates/stock/location.html:91
+#: stock/templates/stock/location.html:90
msgid "Location Description"
msgstr ""
-#: stock/templates/stock/location.html:96
+#: stock/templates/stock/location.html:95
msgid "Sublocations"
msgstr ""
-#: stock/templates/stock/location.html:101
-#: stock/templates/stock/location.html:116
+#: stock/templates/stock/location.html:100
+#: stock/templates/stock/location.html:115
#: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48
#: templates/stats.html:57 users/models.py:35
msgid "Stock Items"
msgstr ""
-#: stock/templates/stock/location.html:106
+#: stock/templates/stock/location.html:105
msgid "Stock Details"
msgstr ""
-#: stock/templates/stock/location.html:111
+#: stock/templates/stock/location.html:110
#: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52
#: users/models.py:34
msgid "Stock Locations"
@@ -4581,14 +4715,8 @@ msgstr ""
msgid "Quantity must not exceed {x}"
msgstr ""
-#: stock/views.py:1132
-#, python-brace-format
-msgid "Added stock to {n} items"
-msgstr ""
-
-#: stock/views.py:1147
-#, python-brace-format
-msgid "Removed stock from {n} items"
+#: stock/views.py:1117
+msgid "No action performed"
msgstr ""
#: stock/views.py:1160
@@ -4760,7 +4888,7 @@ msgstr ""
msgid "Global InvenTree Settings"
msgstr ""
-#: templates/InvenTree/settings/global.html:24
+#: templates/InvenTree/settings/global.html:25
msgid "Barcode Settings"
msgstr ""
@@ -4788,6 +4916,10 @@ msgstr ""
msgid "Purchase Order Settings"
msgstr ""
+#: templates/InvenTree/settings/report.html:10
+msgid "Report Settings"
+msgstr ""
+
#: templates/InvenTree/settings/setting.html:23
msgid "No value set"
msgstr ""
@@ -4797,7 +4929,7 @@ msgid "Edit setting"
msgstr ""
#: templates/InvenTree/settings/settings.html:7
-#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:66
+#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:76
msgid "Settings"
msgstr ""
@@ -4809,7 +4941,7 @@ msgstr ""
msgid "Stock Settings"
msgstr ""
-#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:46
+#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:48
msgid "Stock Options"
msgstr ""
@@ -4835,6 +4967,10 @@ msgid "Global"
msgstr ""
#: templates/InvenTree/settings/tabs.html:19
+msgid "Report"
+msgstr ""
+
+#: templates/InvenTree/settings/tabs.html:22
msgid "Categories"
msgstr ""
@@ -4865,6 +5001,7 @@ msgid "Change Password"
msgstr ""
#: templates/InvenTree/settings/user.html:28
+#: templates/registration/login.html:58
msgid "Username"
msgstr ""
@@ -5121,7 +5258,7 @@ msgstr ""
msgid "Build stock"
msgstr ""
-#: templates/js/build.js:582 templates/stock_table.html:55
+#: templates/js/build.js:582 templates/stock_table.html:57
msgid "Order stock"
msgstr ""
@@ -5133,11 +5270,16 @@ msgstr ""
msgid "No builds matching query"
msgstr ""
-#: templates/js/build.js:656
+#: templates/js/build.js:642 templates/js/part.js:343 templates/js/stock.js:474
+#: templates/js/stock.js:1209
+msgid "Select"
+msgstr ""
+
+#: templates/js/build.js:662
msgid "Build order is overdue"
msgstr ""
-#: templates/js/build.js:747
+#: templates/js/build.js:760
msgid "No parts allocated for"
msgstr ""
@@ -5165,7 +5307,7 @@ msgstr ""
msgid "Assembled part"
msgstr ""
-#: templates/js/label.js:10 templates/js/report.js:89
+#: templates/js/label.js:10 templates/js/report.js:98
msgid "Select Stock Items"
msgstr ""
@@ -5193,11 +5335,11 @@ msgstr ""
msgid "No labels found which match selected stock location(s)"
msgstr ""
-#: templates/js/label.js:142 templates/js/report.js:38
+#: templates/js/label.js:142
msgid "stock items selected"
msgstr ""
-#: templates/js/label.js:150 templates/js/report.js:46
+#: templates/js/label.js:150
msgid "Select Label"
msgstr ""
@@ -5209,11 +5351,11 @@ msgstr ""
msgid "Show Error Information"
msgstr ""
-#: templates/js/modals.js:473
+#: templates/js/modals.js:473 templates/modals.html:64
msgid "Accept"
msgstr ""
-#: templates/js/modals.js:474
+#: templates/js/modals.js:474 templates/modals.html:63
msgid "Cancel"
msgstr ""
@@ -5222,12 +5364,12 @@ msgid "Loading Data"
msgstr ""
#: templates/js/modals.js:549 templates/js/modals.js:807
-#: templates/modals.html:19 templates/modals.html:41
+#: templates/modals.html:22 templates/modals.html:44
msgid "Submit"
msgstr ""
#: templates/js/modals.js:550 templates/js/modals.js:808
-#: templates/modals.html:18 templates/modals.html:40
+#: templates/modals.html:21 templates/modals.html:43 templates/modals.html:82
msgid "Close"
msgstr ""
@@ -5307,10 +5449,6 @@ msgstr ""
msgid "Order is overdue"
msgstr ""
-#: templates/js/order.js:193 templates/js/stock.js:862
-msgid "Date"
-msgstr ""
-
#: templates/js/order.js:229
msgid "No sales orders found"
msgstr ""
@@ -5343,11 +5481,6 @@ msgstr ""
msgid "No parts found"
msgstr ""
-#: templates/js/part.js:343 templates/js/stock.js:474
-#: templates/js/stock.js:1209
-msgid "Select"
-msgstr ""
-
#: templates/js/part.js:411
msgid "No category"
msgstr ""
@@ -5384,22 +5517,55 @@ msgstr ""
msgid "This test is defined for a parent part"
msgstr ""
-#: templates/js/report.js:61
+#: templates/js/report.js:47
+msgid "items selected"
+msgstr ""
+
+#: templates/js/report.js:55
+msgid "Select Report Template"
+msgstr ""
+
+#: templates/js/report.js:70
msgid "Select Test Report Template"
msgstr ""
-#: templates/js/report.js:90
+#: templates/js/report.js:99
msgid "Stock item(s) must be selected before printing reports"
msgstr ""
-#: templates/js/report.js:107
+#: templates/js/report.js:116 templates/js/report.js:169
+#: templates/js/report.js:223
msgid "No Reports Found"
msgstr ""
-#: templates/js/report.js:108
+#: templates/js/report.js:117
msgid "No report templates found which match selected stock item(s)"
msgstr ""
+#: templates/js/report.js:152
+msgid "Select Builds"
+msgstr ""
+
+#: templates/js/report.js:153
+msgid "Build(s) must be selected before printing reports"
+msgstr ""
+
+#: templates/js/report.js:170
+msgid "No report templates found which match selected build(s)"
+msgstr ""
+
+#: templates/js/report.js:205
+msgid "Select Parts"
+msgstr ""
+
+#: templates/js/report.js:206
+msgid "Part(s) must be selected before printing reports"
+msgstr ""
+
+#: templates/js/report.js:224
+msgid "No report templates found which match selected part(s)"
+msgstr ""
+
#: templates/js/stock.js:38
msgid "PASS"
msgstr ""
@@ -5673,95 +5839,111 @@ msgstr ""
msgid "Purchasable"
msgstr ""
-#: templates/js/tables.js:276
+#: templates/js/tables.js:268
msgid "Loading data"
msgstr ""
-#: templates/js/tables.js:279
+#: templates/js/tables.js:271
msgid "rows per page"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "Showing"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "to"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "of"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "rows"
msgstr ""
-#: templates/js/tables.js:285 templates/search_form.html:6
+#: templates/js/tables.js:277 templates/search_form.html:6
#: templates/search_form.html:8
msgid "Search"
msgstr ""
-#: templates/js/tables.js:288
+#: templates/js/tables.js:280
msgid "No matching results"
msgstr ""
-#: templates/js/tables.js:291
+#: templates/js/tables.js:283
msgid "Hide/Show pagination"
msgstr ""
-#: templates/js/tables.js:294
+#: templates/js/tables.js:286
msgid "Refresh"
msgstr ""
-#: templates/js/tables.js:297
+#: templates/js/tables.js:289
msgid "Toggle"
msgstr ""
-#: templates/js/tables.js:300
+#: templates/js/tables.js:292
msgid "Columns"
msgstr ""
-#: templates/js/tables.js:303
+#: templates/js/tables.js:295
msgid "All"
msgstr ""
-#: templates/modals.html:13 templates/modals.html:35
+#: templates/modals.html:14 templates/modals.html:38
msgid "Form errors exist"
msgstr ""
-#: templates/navbar.html:29
+#: templates/navbar.html:33
msgid "Buy"
msgstr ""
-#: templates/navbar.html:39
+#: templates/navbar.html:43
msgid "Sell"
msgstr ""
-#: templates/navbar.html:50
+#: templates/navbar.html:55
msgid "Scan Barcode"
msgstr ""
-#: templates/navbar.html:57
+#: templates/navbar.html:63
msgid "InvenTree server issues detected"
msgstr ""
-#: templates/navbar.html:63 users/models.py:31
+#: templates/navbar.html:69 users/models.py:31
msgid "Admin"
msgstr ""
-#: templates/navbar.html:67
+#: templates/navbar.html:71
msgid "Logout"
msgstr ""
-#: templates/navbar.html:69 templates/registration/login.html:43
+#: templates/navbar.html:73 templates/registration/login.html:89
msgid "Login"
msgstr ""
-#: templates/navbar.html:80
+#: templates/navbar.html:85
msgid "About InvenTree"
msgstr ""
+#: templates/registration/login.html:64
+msgid "Enter username"
+msgstr ""
+
+#: templates/registration/login.html:70
+msgid "Password"
+msgstr ""
+
+#: templates/registration/login.html:76
+msgid "Enter password"
+msgstr ""
+
+#: templates/registration/login.html:83
+msgid "Username / password combination is incorrect"
+msgstr ""
+
#: templates/stats.html:9
msgid "Server"
msgstr ""
@@ -5798,47 +5980,47 @@ msgstr ""
msgid "Print labels"
msgstr ""
-#: templates/stock_table.html:41
+#: templates/stock_table.html:42
msgid "Print test reports"
msgstr ""
-#: templates/stock_table.html:51
+#: templates/stock_table.html:53
msgid "Add to selected stock items"
msgstr ""
-#: templates/stock_table.html:52
+#: templates/stock_table.html:54
msgid "Remove from selected stock items"
msgstr ""
-#: templates/stock_table.html:53
+#: templates/stock_table.html:55
msgid "Stocktake selected stock items"
msgstr ""
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
msgid "Move selected stock items"
msgstr ""
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
msgid "Move stock"
msgstr ""
-#: templates/stock_table.html:55
+#: templates/stock_table.html:57
msgid "Order selected items"
msgstr ""
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
msgid "Change status"
msgstr ""
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
msgid "Change stock status"
msgstr ""
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
msgid "Delete selected items"
msgstr ""
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
msgid "Delete Stock"
msgstr ""
@@ -5866,38 +6048,38 @@ msgstr ""
msgid "Important dates"
msgstr ""
-#: users/models.py:147
+#: users/models.py:150
msgid "Permission set"
msgstr ""
-#: users/models.py:155
+#: users/models.py:158
msgid "Group"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "View"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "Permission to view items"
msgstr ""
-#: users/models.py:160
+#: users/models.py:163
msgid "Add"
msgstr ""
-#: users/models.py:160
+#: users/models.py:163
msgid "Permission to add items"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Change"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Permissions to edit items"
msgstr ""
-#: users/models.py:164
+#: users/models.py:167
msgid "Permission to delete items"
msgstr ""
diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po
index 4236df6f39..c7eadc80ac 100644
--- a/InvenTree/locale/es/LC_MESSAGES/django.po
+++ b/InvenTree/locale/es/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-01-29 12:04+1100\n"
+"POT-Creation-Date: 2021-02-16 22:33+1100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -30,7 +30,7 @@ msgstr ""
msgid "Enter date"
msgstr ""
-#: InvenTree/forms.py:110 build/forms.py:90 build/forms.py:178
+#: InvenTree/forms.py:110 build/forms.py:92 build/forms.py:180
msgid "Confirm"
msgstr ""
@@ -95,12 +95,14 @@ msgstr ""
msgid "File comment"
msgstr ""
-#: InvenTree/models.py:68 templates/js/stock.js:919
+#: InvenTree/models.py:68
+#: report/templates/report/inventree_test_report_base.html:91
+#: templates/js/stock.js:919
msgid "User"
msgstr ""
-#: InvenTree/models.py:106 label/models.py:68 part/models.py:654
-#: part/templates/part/params.html:24 report/models.py:152
+#: InvenTree/models.py:106 label/models.py:69 part/models.py:654
+#: part/templates/part/params.html:24 report/models.py:162
#: templates/js/part.js:129
msgid "Name"
msgstr ""
@@ -109,23 +111,23 @@ msgstr ""
msgid "Description (optional)"
msgstr ""
-#: InvenTree/settings.py:454
+#: InvenTree/settings.py:446
msgid "English"
msgstr ""
-#: InvenTree/settings.py:455
+#: InvenTree/settings.py:447
msgid "French"
msgstr ""
-#: InvenTree/settings.py:456
+#: InvenTree/settings.py:448
msgid "German"
msgstr ""
-#: InvenTree/settings.py:457
+#: InvenTree/settings.py:449
msgid "Polish"
msgstr ""
-#: InvenTree/settings.py:458
+#: InvenTree/settings.py:450
msgid "Turkish"
msgstr ""
@@ -248,7 +250,7 @@ msgstr ""
msgid "Password fields must match"
msgstr ""
-#: InvenTree/views.py:795 templates/navbar.html:78
+#: InvenTree/views.py:795 templates/navbar.html:83
msgid "System Information"
msgstr ""
@@ -300,14 +302,14 @@ msgstr ""
msgid "Order target date"
msgstr ""
-#: build/forms.py:39 build/models.py:206
+#: build/forms.py:39 build/models.py:210
msgid ""
"Target date for build completion. Build will be overdue after this date."
msgstr ""
-#: build/forms.py:78 build/templates/build/auto_allocate.html:17
-#: build/templates/build/build_base.html:83
-#: build/templates/build/detail.html:29 common/models.py:610
+#: build/forms.py:80 build/templates/build/auto_allocate.html:17
+#: build/templates/build/build_base.html:91
+#: build/templates/build/detail.html:29 common/models.py:647
#: company/forms.py:112 company/templates/company/supplier_part_pricing.html:75
#: order/templates/order/order_wizard/select_parts.html:32
#: order/templates/order/purchase_order_detail.html:179
@@ -315,285 +317,302 @@ msgstr ""
#: order/templates/order/sales_order_detail.html:156
#: part/templates/part/allocation.html:16
#: part/templates/part/allocation.html:49
-#: part/templates/part/sale_prices.html:82 stock/forms.py:306
-#: stock/templates/stock/item_base.html:51
+#: part/templates/part/sale_prices.html:82
+#: report/templates/report/inventree_build_order_base.html:116
+#: report/templates/report/inventree_test_report_base.html:77
+#: stock/forms.py:306 stock/templates/stock/item_base.html:51
#: stock/templates/stock/item_base.html:57
-#: stock/templates/stock/item_base.html:238
+#: stock/templates/stock/item_base.html:234
#: stock/templates/stock/stock_adjust.html:18 templates/js/barcode.js:364
#: templates/js/bom.js:195 templates/js/build.js:420 templates/js/stock.js:910
#: templates/js/stock.js:1149
msgid "Quantity"
msgstr ""
-#: build/forms.py:79
+#: build/forms.py:81
msgid "Enter quantity for build output"
msgstr ""
-#: build/forms.py:83 stock/forms.py:117
+#: build/forms.py:85 stock/forms.py:117
msgid "Serial numbers"
msgstr ""
-#: build/forms.py:85
+#: build/forms.py:87
msgid "Enter serial numbers for build outputs"
msgstr ""
-#: build/forms.py:91
+#: build/forms.py:93
msgid "Confirm creation of build outut"
msgstr ""
-#: build/forms.py:111
+#: build/forms.py:113
msgid "Confirm deletion of build output"
msgstr ""
-#: build/forms.py:132
+#: build/forms.py:134
msgid "Confirm unallocation of stock"
msgstr ""
-#: build/forms.py:156
+#: build/forms.py:158
msgid "Confirm stock allocation"
msgstr ""
-#: build/forms.py:179
+#: build/forms.py:181
msgid "Mark build as complete"
msgstr ""
-#: build/forms.py:203
+#: build/forms.py:205
msgid "Location of completed parts"
msgstr ""
-#: build/forms.py:208
+#: build/forms.py:210
msgid "Confirm completion with incomplete stock allocation"
msgstr ""
-#: build/forms.py:211
+#: build/forms.py:213
msgid "Confirm build completion"
msgstr ""
-#: build/forms.py:231 build/views.py:68
+#: build/forms.py:233 build/views.py:68
msgid "Confirm build cancellation"
msgstr ""
-#: build/forms.py:245
+#: build/forms.py:247
msgid "Select quantity of stock to allocate"
msgstr ""
-#: build/models.py:61 build/templates/build/build_base.html:8
+#: build/models.py:65 build/templates/build/build_base.html:8
#: build/templates/build/build_base.html:35
#: part/templates/part/allocation.html:20
+#: report/templates/report/inventree_build_order_base.html:108
msgid "Build Order"
msgstr ""
-#: build/models.py:62 build/templates/build/index.html:8
+#: build/models.py:66 build/templates/build/index.html:8
#: build/templates/build/index.html:15 order/templates/order/so_builds.html:11
#: order/templates/order/so_tabs.html:9 part/templates/part/tabs.html:31
-#: templates/InvenTree/settings/tabs.html:28 users/models.py:36
+#: templates/InvenTree/settings/tabs.html:31 users/models.py:36
msgid "Build Orders"
msgstr ""
-#: build/models.py:108
+#: build/models.py:112
msgid "Build Order Reference"
msgstr ""
-#: build/models.py:109 order/templates/order/purchase_order_detail.html:174
+#: build/models.py:113 order/templates/order/purchase_order_detail.html:174
#: templates/js/bom.js:187 templates/js/build.js:509
msgid "Reference"
msgstr ""
-#: build/models.py:116 build/templates/build/detail.html:19
+#: build/models.py:120 build/templates/build/detail.html:19
#: company/models.py:359 company/templates/company/detail.html:23
#: company/templates/company/supplier_part_base.html:61
-#: company/templates/company/supplier_part_detail.html:27 label/models.py:75
+#: company/templates/company/supplier_part_detail.html:27 label/models.py:76
#: order/templates/order/purchase_order_detail.html:161 part/models.py:678
#: part/templates/part/detail.html:51 part/templates/part/set_category.html:14
-#: report/models.py:166 templates/InvenTree/search.html:147
+#: report/models.py:175
+#: report/templates/report/inventree_build_order_base.html:120
+#: templates/InvenTree/search.html:147
#: templates/InvenTree/settings/header.html:9 templates/js/bom.js:180
-#: templates/js/bom.js:547 templates/js/build.js:664 templates/js/company.js:56
+#: templates/js/bom.js:547 templates/js/build.js:670 templates/js/company.js:56
#: templates/js/order.js:180 templates/js/order.js:274 templates/js/part.js:188
#: templates/js/part.js:271 templates/js/part.js:391 templates/js/part.js:586
#: templates/js/stock.js:512 templates/js/stock.js:891
msgid "Description"
msgstr ""
-#: build/models.py:119
+#: build/models.py:123
msgid "Brief description of the build"
msgstr ""
-#: build/models.py:128 build/templates/build/build_base.html:113
+#: build/models.py:132 build/templates/build/build_base.html:121
#: build/templates/build/detail.html:75
msgid "Parent Build"
msgstr ""
-#: build/models.py:129
+#: build/models.py:133
msgid "BuildOrder to which this build is allocated"
msgstr ""
-#: build/models.py:134 build/templates/build/auto_allocate.html:16
-#: build/templates/build/build_base.html:78
+#: build/models.py:138 build/templates/build/auto_allocate.html:16
+#: build/templates/build/build_base.html:86
#: build/templates/build/detail.html:24 order/models.py:652
#: order/templates/order/order_wizard/select_parts.html:30
#: order/templates/order/purchase_order_detail.html:148
#: order/templates/order/receive_parts.html:19 part/models.py:320
#: part/templates/part/part_app_base.html:7 part/templates/part/related.html:26
-#: part/templates/part/set_category.html:13 templates/InvenTree/search.html:133
-#: templates/js/barcode.js:362 templates/js/bom.js:153 templates/js/bom.js:532
-#: templates/js/build.js:669 templates/js/company.js:138
-#: templates/js/part.js:252 templates/js/part.js:357 templates/js/stock.js:486
+#: part/templates/part/set_category.html:13
+#: report/templates/report/inventree_build_order_base.html:112
+#: templates/InvenTree/search.html:133 templates/js/barcode.js:362
+#: templates/js/bom.js:153 templates/js/bom.js:532 templates/js/build.js:675
+#: templates/js/company.js:138 templates/js/part.js:252
+#: templates/js/part.js:357 templates/js/stock.js:486
#: templates/js/stock.js:1221
msgid "Part"
msgstr ""
-#: build/models.py:142
+#: build/models.py:146
msgid "Select part to build"
msgstr ""
-#: build/models.py:147
+#: build/models.py:151
msgid "Sales Order Reference"
msgstr ""
-#: build/models.py:151
+#: build/models.py:155
msgid "SalesOrder to which this build is allocated"
msgstr ""
-#: build/models.py:156
+#: build/models.py:160
msgid "Source Location"
msgstr ""
-#: build/models.py:160
+#: build/models.py:164
msgid ""
"Select location to take stock from for this build (leave blank to take from "
"any stock location)"
msgstr ""
-#: build/models.py:165
+#: build/models.py:169
msgid "Destination Location"
msgstr ""
-#: build/models.py:169
+#: build/models.py:173
msgid "Select location where the completed items will be stored"
msgstr ""
-#: build/models.py:173
+#: build/models.py:177
msgid "Build Quantity"
msgstr ""
-#: build/models.py:176
+#: build/models.py:180
msgid "Number of stock items to build"
msgstr ""
-#: build/models.py:180
+#: build/models.py:184
msgid "Completed items"
msgstr ""
-#: build/models.py:182
+#: build/models.py:186
msgid "Number of stock items which have been completed"
msgstr ""
-#: build/models.py:186 part/templates/part/part_base.html:158
+#: build/models.py:190 part/templates/part/part_base.html:157
msgid "Build Status"
msgstr ""
-#: build/models.py:190
+#: build/models.py:194
msgid "Build status code"
msgstr ""
-#: build/models.py:194 stock/models.py:418
+#: build/models.py:198 stock/models.py:421
msgid "Batch Code"
msgstr ""
-#: build/models.py:198
+#: build/models.py:202
msgid "Batch code for this build output"
msgstr ""
-#: build/models.py:205 order/models.py:437
+#: build/models.py:209 order/models.py:437
msgid "Target completion date"
msgstr ""
-#: build/models.py:219 build/templates/build/detail.html:89
+#: build/models.py:226
+msgid "User who issued this build order"
+msgstr ""
+
+#: build/models.py:234
+msgid "User responsible for this build order"
+msgstr ""
+
+#: build/models.py:239 build/templates/build/detail.html:89
#: company/templates/company/supplier_part_base.html:68
#: company/templates/company/supplier_part_detail.html:24
-#: part/templates/part/detail.html:80 part/templates/part/part_base.html:105
-#: stock/models.py:412 stock/templates/stock/item_base.html:321
+#: part/templates/part/detail.html:80 part/templates/part/part_base.html:104
+#: stock/models.py:415 stock/templates/stock/item_base.html:317
msgid "External Link"
msgstr ""
-#: build/models.py:220 part/models.py:712 stock/models.py:414
+#: build/models.py:240 part/models.py:712 stock/models.py:417
msgid "Link to external URL"
msgstr ""
-#: build/models.py:224 build/templates/build/tabs.html:23 company/models.py:366
+#: build/models.py:244 build/templates/build/tabs.html:23 company/models.py:366
#: company/templates/company/tabs.html:33 order/templates/order/po_tabs.html:18
#: order/templates/order/purchase_order_detail.html:213
#: order/templates/order/so_tabs.html:23 part/models.py:838
-#: part/templates/part/tabs.html:73 stock/forms.py:315 stock/forms.py:347
-#: stock/forms.py:375 stock/models.py:484 stock/models.py:1554
-#: stock/templates/stock/tabs.html:26 templates/js/barcode.js:37
-#: templates/js/bom.js:293 templates/js/stock.js:128 templates/js/stock.js:624
+#: part/templates/part/tabs.html:73
+#: report/templates/report/inventree_build_order_base.html:175
+#: stock/forms.py:315 stock/forms.py:347 stock/forms.py:375 stock/models.py:487
+#: stock/models.py:1582 stock/templates/stock/tabs.html:26
+#: templates/js/barcode.js:37 templates/js/bom.js:293 templates/js/stock.js:128
+#: templates/js/stock.js:624
msgid "Notes"
msgstr ""
-#: build/models.py:225
+#: build/models.py:245
msgid "Extra build notes"
msgstr ""
-#: build/models.py:607
+#: build/models.py:627
msgid "No build output specified"
msgstr ""
-#: build/models.py:610
+#: build/models.py:630
msgid "Build output is already completed"
msgstr ""
-#: build/models.py:613
+#: build/models.py:633
msgid "Build output does not match Build Order"
msgstr ""
-#: build/models.py:688
+#: build/models.py:708
msgid "Completed build output"
msgstr ""
-#: build/models.py:930
+#: build/models.py:950
msgid "BuildItem must be unique for build, stock_item and install_into"
msgstr ""
-#: build/models.py:952
+#: build/models.py:972
msgid "Build item must specify a build output"
msgstr ""
-#: build/models.py:957
+#: build/models.py:977
#, python-brace-format
msgid "Selected stock item not found in BOM for part '{p}'"
msgstr ""
-#: build/models.py:961
+#: build/models.py:981
#, python-brace-format
msgid "Allocated quantity ({n}) must not exceed available quantity ({q})"
msgstr ""
-#: build/models.py:968 order/models.py:736
+#: build/models.py:988 order/models.py:736
msgid "StockItem is over-allocated"
msgstr ""
-#: build/models.py:972 order/models.py:739
+#: build/models.py:992 order/models.py:739
msgid "Allocation quantity must be greater than zero"
msgstr ""
-#: build/models.py:976
+#: build/models.py:996
msgid "Quantity must be 1 for serialized stock"
msgstr ""
-#: build/models.py:1016
+#: build/models.py:1036
msgid "Build to allocate parts"
msgstr ""
-#: build/models.py:1023
+#: build/models.py:1043
msgid "Source stock item"
msgstr ""
-#: build/models.py:1035
+#: build/models.py:1055
msgid "Stock quantity to allocate to build"
msgstr ""
-#: build/models.py:1043
+#: build/models.py:1063
msgid "Destination stock item"
msgstr ""
@@ -627,7 +646,7 @@ msgstr ""
msgid "Unallocate stock"
msgstr ""
-#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:778
+#: build/templates/build/allocate.html:34 build/views.py:341 build/views.py:781
msgid "Unallocate Stock"
msgstr ""
@@ -659,7 +678,7 @@ msgid ""
msgstr ""
#: build/templates/build/auto_allocate.html:18 stock/forms.py:345
-#: stock/templates/stock/item_base.html:268
+#: stock/templates/stock/item_base.html:264
#: stock/templates/stock/stock_adjust.html:17
#: templates/InvenTree/search.html:183 templates/js/barcode.js:363
#: templates/js/barcode.js:531 templates/js/build.js:434
@@ -694,7 +713,7 @@ msgid "Admin view"
msgstr ""
#: build/templates/build/build_base.html:43
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
#: order/templates/order/order_base.html:32
#: order/templates/order/order_base.html:83
#: order/templates/order/sales_order_base.html:41
@@ -704,64 +723,87 @@ msgstr ""
msgid "Overdue"
msgstr ""
-#: build/templates/build/build_base.html:51
+#: build/templates/build/build_base.html:52
+msgid "Print actions"
+msgstr ""
+
+#: build/templates/build/build_base.html:56
+msgid "Print Build Order"
+msgstr ""
+
+#: build/templates/build/build_base.html:62
+msgid "Build actions"
+msgstr ""
+
+#: build/templates/build/build_base.html:66
msgid "Edit Build"
msgstr ""
-#: build/templates/build/build_base.html:55
+#: build/templates/build/build_base.html:68
msgid "Complete Build"
msgstr ""
-#: build/templates/build/build_base.html:58 build/views.py:58
+#: build/templates/build/build_base.html:69 build/views.py:58
msgid "Cancel Build"
msgstr ""
-#: build/templates/build/build_base.html:64
-msgid "Delete Build"
-msgstr ""
-
-#: build/templates/build/build_base.html:74 build/templates/build/detail.html:9
+#: build/templates/build/build_base.html:82 build/templates/build/detail.html:9
msgid "Build Details"
msgstr ""
-#: build/templates/build/build_base.html:88
+#: build/templates/build/build_base.html:96
#: build/templates/build/detail.html:57
#: order/templates/order/receive_parts.html:24
-#: stock/templates/stock/item_base.html:367 templates/InvenTree/search.html:175
-#: templates/js/barcode.js:119 templates/js/build.js:697
+#: stock/templates/stock/item_base.html:363 templates/InvenTree/search.html:175
+#: templates/js/barcode.js:119 templates/js/build.js:703
#: templates/js/order.js:185 templates/js/order.js:279
#: templates/js/stock.js:585 templates/js/stock.js:1157
msgid "Status"
msgstr ""
-#: build/templates/build/build_base.html:96
-#: build/templates/build/detail.html:100
+#: build/templates/build/build_base.html:104
+#: build/templates/build/detail.html:119
#: order/templates/order/order_base.html:121
-#: order/templates/order/sales_order_base.html:114 templates/js/build.js:710
-#: templates/js/order.js:198 templates/js/order.js:292
+#: order/templates/order/sales_order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:128
+#: templates/js/build.js:716 templates/js/order.js:198
+#: templates/js/order.js:292
msgid "Target Date"
msgstr ""
-#: build/templates/build/build_base.html:100
+#: build/templates/build/build_base.html:108
msgid "This build was due on"
msgstr ""
-#: build/templates/build/build_base.html:107
+#: build/templates/build/build_base.html:115
#: build/templates/build/detail.html:62
msgid "Progress"
msgstr ""
-#: build/templates/build/build_base.html:120
+#: build/templates/build/build_base.html:128
#: build/templates/build/detail.html:82 order/models.py:650
#: order/templates/order/sales_order_base.html:9
#: order/templates/order/sales_order_base.html:33
#: order/templates/order/sales_order_notes.html:10
#: order/templates/order/sales_order_ship.html:25
#: part/templates/part/allocation.html:27
-#: stock/templates/stock/item_base.html:262 templates/js/order.js:240
+#: report/templates/report/inventree_build_order_base.html:138
+#: stock/templates/stock/item_base.html:258 templates/js/order.js:240
msgid "Sales Order"
msgstr ""
+#: build/templates/build/build_base.html:135
+#: build/templates/build/detail.html:96
+#: report/templates/report/inventree_build_order_base.html:155
+msgid "Issued By"
+msgstr ""
+
+#: build/templates/build/build_base.html:142
+#: build/templates/build/detail.html:103
+#: report/templates/report/inventree_build_order_base.html:161
+msgid "Responsible"
+msgstr ""
+
#: build/templates/build/build_output.html:9 build/templates/build/tabs.html:17
msgid "Build Outputs"
msgstr ""
@@ -859,28 +901,28 @@ msgid "Destination location not specified"
msgstr ""
#: build/templates/build/detail.html:68
-#: stock/templates/stock/item_base.html:286 templates/js/stock.js:593
+#: stock/templates/stock/item_base.html:282 templates/js/stock.js:593
#: templates/js/stock.js:1164 templates/js/table_filters.js:80
#: templates/js/table_filters.js:161
msgid "Batch"
msgstr ""
-#: build/templates/build/detail.html:95
+#: build/templates/build/detail.html:114
#: order/templates/order/order_base.html:108
-#: order/templates/order/sales_order_base.html:108 templates/js/build.js:705
+#: order/templates/order/sales_order_base.html:108 templates/js/build.js:711
msgid "Created"
msgstr ""
-#: build/templates/build/detail.html:106
+#: build/templates/build/detail.html:125
msgid "No target date set"
msgstr ""
-#: build/templates/build/detail.html:111 templates/js/build.js:683
-#: templates/js/build.js:715
+#: build/templates/build/detail.html:130 templates/js/build.js:689
+#: templates/js/build.js:721
msgid "Completed"
msgstr ""
-#: build/templates/build/detail.html:115
+#: build/templates/build/detail.html:134
msgid "Build not complete"
msgstr ""
@@ -888,17 +930,21 @@ msgstr ""
msgid "Alter the quantity of stock allocated to the build output"
msgstr ""
-#: build/templates/build/index.html:27 build/views.py:658
+#: build/templates/build/index.html:28 build/views.py:658
msgid "New Build Order"
msgstr ""
-#: build/templates/build/index.html:30
+#: build/templates/build/index.html:37 build/templates/build/index.html:38
+msgid "Print Build Orders"
+msgstr ""
+
+#: build/templates/build/index.html:43
#: order/templates/order/purchase_orders.html:22
#: order/templates/order/sales_orders.html:22
msgid "Display calendar view"
msgstr ""
-#: build/templates/build/index.html:33
+#: build/templates/build/index.html:46
#: order/templates/order/purchase_orders.html:25
#: order/templates/order/sales_orders.html:25
msgid "Display list view"
@@ -959,7 +1005,7 @@ msgstr ""
msgid "Create Build Output"
msgstr ""
-#: build/views.py:207 stock/models.py:897 stock/views.py:1804
+#: build/views.py:207 stock/models.py:900 stock/views.py:1804
msgid "Serial numbers already exist"
msgstr ""
@@ -1015,77 +1061,77 @@ msgstr ""
msgid "Build output completed"
msgstr ""
-#: build/views.py:703
+#: build/views.py:706
msgid "Created new build"
msgstr ""
-#: build/views.py:724
+#: build/views.py:727
msgid "Edit Build Order Details"
msgstr ""
-#: build/views.py:758
+#: build/views.py:761
msgid "Edited build"
msgstr ""
-#: build/views.py:767
+#: build/views.py:770
msgid "Delete Build Order"
msgstr ""
-#: build/views.py:784
+#: build/views.py:787
msgid "Removed parts from build allocation"
msgstr ""
-#: build/views.py:796
+#: build/views.py:799
msgid "Allocate stock to build output"
msgstr ""
-#: build/views.py:840
+#: build/views.py:843
msgid "Item must be currently in stock"
msgstr ""
-#: build/views.py:846
+#: build/views.py:849
msgid "Stock item is over-allocated"
msgstr ""
-#: build/views.py:847 templates/js/bom.js:220 templates/js/build.js:519
-#: templates/js/build.js:758
+#: build/views.py:850 templates/js/bom.js:220 templates/js/build.js:519
+#: templates/js/build.js:771
msgid "Available"
msgstr ""
-#: build/views.py:849
+#: build/views.py:852
msgid "Stock item must be selected"
msgstr ""
-#: build/views.py:1012
+#: build/views.py:1015
msgid "Edit Stock Allocation"
msgstr ""
-#: build/views.py:1017
+#: build/views.py:1020
msgid "Updated Build Item"
msgstr ""
-#: build/views.py:1046
+#: build/views.py:1049
msgid "Add Build Order Attachment"
msgstr ""
-#: build/views.py:1060 order/views.py:113 order/views.py:166 part/views.py:170
+#: build/views.py:1063 order/views.py:113 order/views.py:166 part/views.py:170
#: stock/views.py:280
msgid "Added attachment"
msgstr ""
-#: build/views.py:1096 order/views.py:193 order/views.py:215
+#: build/views.py:1099 order/views.py:193 order/views.py:215
msgid "Edit Attachment"
msgstr ""
-#: build/views.py:1107 order/views.py:198 order/views.py:220
+#: build/views.py:1110 order/views.py:198 order/views.py:220
msgid "Attachment updated"
msgstr ""
-#: build/views.py:1117 order/views.py:235 order/views.py:250
+#: build/views.py:1120 order/views.py:235 order/views.py:250
msgid "Delete Attachment"
msgstr ""
-#: build/views.py:1123 order/views.py:242 order/views.py:257 stock/views.py:338
+#: build/views.py:1126 order/views.py:242 order/views.py:257 stock/views.py:338
msgid "Deleted attachment"
msgstr ""
@@ -1106,250 +1152,282 @@ msgid "Internal company name"
msgstr ""
#: common/models.py:68
-msgid "Default Currency"
+msgid "Base URL"
msgstr ""
#: common/models.py:69
-msgid "Default currency"
+msgid "Base URL for server instance"
msgstr ""
#: common/models.py:75
-msgid "Barcode Support"
+msgid "Default Currency"
msgstr ""
#: common/models.py:76
-msgid "Enable barcode scanner support"
+msgid "Default currency"
msgstr ""
#: common/models.py:82
-msgid "IPN Regex"
+msgid "Barcode Support"
msgstr ""
#: common/models.py:83
+msgid "Enable barcode scanner support"
+msgstr ""
+
+#: common/models.py:89
+msgid "IPN Regex"
+msgstr ""
+
+#: common/models.py:90
msgid "Regular expression pattern for matching Part IPN"
msgstr ""
-#: common/models.py:87
+#: common/models.py:94
msgid "Allow Duplicate IPN"
msgstr ""
-#: common/models.py:88
+#: common/models.py:95
msgid "Allow multiple parts to share the same IPN"
msgstr ""
-#: common/models.py:94
+#: common/models.py:101
msgid "Copy Part BOM Data"
msgstr ""
-#: common/models.py:95
+#: common/models.py:102
msgid "Copy BOM data by default when duplicating a part"
msgstr ""
-#: common/models.py:101
+#: common/models.py:108
msgid "Copy Part Parameter Data"
msgstr ""
-#: common/models.py:102
+#: common/models.py:109
msgid "Copy parameter data by default when duplicating a part"
msgstr ""
-#: common/models.py:108
+#: common/models.py:115
msgid "Copy Part Test Data"
msgstr ""
-#: common/models.py:109
+#: common/models.py:116
msgid "Copy test data by default when duplicating a part"
msgstr ""
-#: common/models.py:115
+#: common/models.py:122
msgid "Copy Category Parameter Templates"
msgstr ""
-#: common/models.py:116
+#: common/models.py:123
msgid "Copy category parameter templates when creating a part"
msgstr ""
-#: common/models.py:122 part/templates/part/detail.html:155
-#: report/models.py:159 stock/forms.py:257 templates/js/table_filters.js:23
+#: common/models.py:129 part/templates/part/detail.html:157
+#: report/models.py:168 stock/forms.py:257 templates/js/table_filters.js:23
#: templates/js/table_filters.js:270
msgid "Template"
msgstr ""
-#: common/models.py:123
+#: common/models.py:130
msgid "Parts are templates by default"
msgstr ""
-#: common/models.py:129 part/models.py:801 part/templates/part/detail.html:165
+#: common/models.py:136 part/models.py:801 part/templates/part/detail.html:167
#: templates/js/table_filters.js:282
msgid "Assembly"
msgstr ""
-#: common/models.py:130
+#: common/models.py:137
msgid "Parts can be assembled from other components by default"
msgstr ""
-#: common/models.py:136 part/models.py:807 part/templates/part/detail.html:175
+#: common/models.py:143 part/models.py:807 part/templates/part/detail.html:177
#: templates/js/table_filters.js:286
msgid "Component"
msgstr ""
-#: common/models.py:137
+#: common/models.py:144
msgid "Parts can be used as sub-components by default"
msgstr ""
-#: common/models.py:143 part/models.py:818 part/templates/part/detail.html:195
+#: common/models.py:150 part/models.py:818 part/templates/part/detail.html:197
msgid "Purchaseable"
msgstr ""
-#: common/models.py:144
+#: common/models.py:151
msgid "Parts are purchaseable by default"
msgstr ""
-#: common/models.py:150 part/models.py:823 part/templates/part/detail.html:205
+#: common/models.py:157 part/models.py:823 part/templates/part/detail.html:207
#: templates/js/table_filters.js:294
msgid "Salable"
msgstr ""
-#: common/models.py:151
+#: common/models.py:158
msgid "Parts are salable by default"
msgstr ""
-#: common/models.py:157 part/models.py:813 part/templates/part/detail.html:185
+#: common/models.py:164 part/models.py:813 part/templates/part/detail.html:187
#: templates/js/table_filters.js:31 templates/js/table_filters.js:298
msgid "Trackable"
msgstr ""
-#: common/models.py:158
+#: common/models.py:165
msgid "Parts are trackable by default"
msgstr ""
-#: common/models.py:164 part/models.py:833 part/templates/part/detail.html:145
+#: common/models.py:171 part/models.py:833 part/templates/part/detail.html:147
#: templates/js/table_filters.js:27
msgid "Virtual"
msgstr ""
-#: common/models.py:165
+#: common/models.py:172
msgid "Parts are virtual by default"
msgstr ""
-#: common/models.py:171
+#: common/models.py:178
msgid "Show Quantity in Forms"
msgstr ""
-#: common/models.py:172
+#: common/models.py:179
msgid "Display available part quantity in some forms"
msgstr ""
-#: common/models.py:178
-msgid "Stock Expiry"
-msgstr ""
-
-#: common/models.py:179
-msgid "Enable stock expiry functionality"
-msgstr ""
-
#: common/models.py:185
-msgid "Sell Expired Stock"
+msgid "Debug Mode"
msgstr ""
#: common/models.py:186
-msgid "Allow sale of expired stock"
+msgid "Generate reports in debug mode (HTML output)"
msgstr ""
#: common/models.py:192
-msgid "Stock Stale Time"
+msgid "Page Size"
msgstr ""
#: common/models.py:193
-msgid "Number of days stock items are considered stale before expiring"
+msgid "Default page size for PDF reports"
msgstr ""
-#: common/models.py:195 part/templates/part/detail.html:116
-msgid "days"
+#: common/models.py:203
+msgid "Test Reports"
msgstr ""
-#: common/models.py:200
-msgid "Build Expired Stock"
+#: common/models.py:204
+msgid "Enable generation of test reports"
msgstr ""
-#: common/models.py:201
-msgid "Allow building with expired stock"
+#: common/models.py:210
+msgid "Stock Expiry"
msgstr ""
-#: common/models.py:207
-msgid "Stock Ownership Control"
+#: common/models.py:211
+msgid "Enable stock expiry functionality"
msgstr ""
-#: common/models.py:208
-msgid "Enable ownership control over stock locations and items"
+#: common/models.py:217
+msgid "Sell Expired Stock"
msgstr ""
-#: common/models.py:214
-msgid "Build Order Reference Prefix"
+#: common/models.py:218
+msgid "Allow sale of expired stock"
msgstr ""
-#: common/models.py:215
-msgid "Prefix value for build order reference"
-msgstr ""
-
-#: common/models.py:220
-msgid "Build Order Reference Regex"
-msgstr ""
-
-#: common/models.py:221
-msgid "Regular expression pattern for matching build order reference"
+#: common/models.py:224
+msgid "Stock Stale Time"
msgstr ""
#: common/models.py:225
-msgid "Sales Order Reference Prefix"
+msgid "Number of days stock items are considered stale before expiring"
msgstr ""
-#: common/models.py:226
-msgid "Prefix value for sales order reference"
-msgstr ""
-
-#: common/models.py:231
-msgid "Purchase Order Reference Prefix"
+#: common/models.py:227 part/templates/part/detail.html:118
+msgid "days"
msgstr ""
#: common/models.py:232
+msgid "Build Expired Stock"
+msgstr ""
+
+#: common/models.py:233
+msgid "Allow building with expired stock"
+msgstr ""
+
+#: common/models.py:239
+msgid "Stock Ownership Control"
+msgstr ""
+
+#: common/models.py:240
+msgid "Enable ownership control over stock locations and items"
+msgstr ""
+
+#: common/models.py:246
+msgid "Build Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:247
+msgid "Prefix value for build order reference"
+msgstr ""
+
+#: common/models.py:252
+msgid "Build Order Reference Regex"
+msgstr ""
+
+#: common/models.py:253
+msgid "Regular expression pattern for matching build order reference"
+msgstr ""
+
+#: common/models.py:257
+msgid "Sales Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:258
+msgid "Prefix value for sales order reference"
+msgstr ""
+
+#: common/models.py:263
+msgid "Purchase Order Reference Prefix"
+msgstr ""
+
+#: common/models.py:264
msgid "Prefix value for purchase order reference"
msgstr ""
-#: common/models.py:455
+#: common/models.py:487
msgid "Settings key (must be unique - case insensitive"
msgstr ""
-#: common/models.py:457
+#: common/models.py:489
msgid "Settings value"
msgstr ""
-#: common/models.py:514
+#: common/models.py:551
msgid "Value must be a boolean value"
msgstr ""
-#: common/models.py:524
+#: common/models.py:561
msgid "Value must be an integer value"
msgstr ""
-#: common/models.py:538
+#: common/models.py:575
msgid "Key string must be unique"
msgstr ""
-#: common/models.py:611 company/forms.py:113
+#: common/models.py:648 company/forms.py:113
msgid "Price break quantity"
msgstr ""
-#: common/models.py:619 company/templates/company/supplier_part_pricing.html:80
+#: common/models.py:656 company/templates/company/supplier_part_pricing.html:80
#: part/templates/part/sale_prices.html:87 templates/js/bom.js:245
msgid "Price"
msgstr ""
-#: common/models.py:620
+#: common/models.py:657
msgid "Unit price at specified quantity"
msgstr ""
-#: common/models.py:643
+#: common/models.py:680
msgid "Default"
msgstr ""
@@ -1450,8 +1528,8 @@ msgstr ""
msgid "Currency"
msgstr ""
-#: company/models.py:313 stock/models.py:366
-#: stock/templates/stock/item_base.html:218
+#: company/models.py:313 stock/models.py:369
+#: stock/templates/stock/item_base.html:214
msgid "Base Part"
msgstr ""
@@ -1464,7 +1542,7 @@ msgstr ""
#: company/templates/company/supplier_part_detail.html:21
#: order/templates/order/order_base.html:89
#: order/templates/order/order_wizard/select_pos.html:30 part/bom.py:170
-#: stock/templates/stock/item_base.html:328 templates/js/company.js:48
+#: stock/templates/stock/item_base.html:324 templates/js/company.js:48
#: templates/js/company.js:164 templates/js/order.js:167
msgid "Supplier"
msgstr ""
@@ -1503,8 +1581,9 @@ msgstr ""
msgid "Manufacturer part number"
msgstr ""
-#: company/models.py:353 part/models.py:711 templates/js/company.js:208
-#: templates/js/part.js:451
+#: company/models.py:353 part/models.py:711
+#: report/templates/report/inventree_build_order_base.html:167
+#: templates/js/company.js:208 templates/js/part.js:451
msgid "Link"
msgstr ""
@@ -1561,8 +1640,8 @@ msgid "Uses default currency"
msgstr ""
#: company/templates/company/detail.html:62
-#: order/templates/order/sales_order_base.html:89 stock/models.py:401
-#: stock/models.py:402 stock/templates/stock/item_base.html:245
+#: order/templates/order/sales_order_base.html:89 stock/models.py:404
+#: stock/models.py:405 stock/templates/stock/item_base.html:241
#: templates/js/company.js:40 templates/js/order.js:261
msgid "Customer"
msgstr ""
@@ -1601,7 +1680,7 @@ msgid "Delete Parts"
msgstr ""
#: company/templates/company/detail_part.html:63
-#: part/templates/part/bom.html:182 part/templates/part/category.html:116
+#: part/templates/part/bom.html:185 part/templates/part/category.html:116
#: templates/js/stock.js:1035
msgid "New Part"
msgstr ""
@@ -1634,8 +1713,8 @@ msgstr ""
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
-#: part/templates/part/bom.html:63 part/templates/part/category.html:112
-#: part/templates/part/category.html:126 part/templates/part/stock.html:51
+#: part/templates/part/category.html:112 part/templates/part/category.html:126
+#: part/templates/part/stock.html:51
msgid "Export"
msgstr ""
@@ -1657,7 +1736,7 @@ msgstr ""
#: order/templates/order/purchase_orders.html:8
#: order/templates/order/purchase_orders.html:13
#: part/templates/part/orders.html:9 part/templates/part/tabs.html:48
-#: templates/InvenTree/settings/tabs.html:31 templates/navbar.html:33
+#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:37
#: users/models.py:37
msgid "Purchase Orders"
msgstr ""
@@ -1677,7 +1756,7 @@ msgstr ""
#: order/templates/order/sales_orders.html:8
#: order/templates/order/sales_orders.html:13
#: part/templates/part/sales_orders.html:9 part/templates/part/tabs.html:56
-#: templates/InvenTree/settings/tabs.html:34 templates/navbar.html:42
+#: templates/InvenTree/settings/tabs.html:37 templates/navbar.html:46
#: users/models.py:38
msgid "Sales Orders"
msgstr ""
@@ -1693,13 +1772,13 @@ msgid "New Sales Order"
msgstr ""
#: company/templates/company/supplier_part_base.html:6
-#: company/templates/company/supplier_part_base.html:19 stock/models.py:375
-#: stock/templates/stock/item_base.html:333 templates/js/company.js:180
+#: company/templates/company/supplier_part_base.html:19 stock/models.py:378
+#: stock/templates/stock/item_base.html:329 templates/js/company.js:180
msgid "Supplier Part"
msgstr ""
#: company/templates/company/supplier_part_base.html:26
-#: part/templates/part/orders.html:14 part/templates/part/part_base.html:69
+#: part/templates/part/orders.html:14 part/templates/part/part_base.html:68
msgid "Order part"
msgstr ""
@@ -1765,8 +1844,8 @@ msgstr ""
#: company/templates/company/supplier_part_tabs.html:8
#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:18
#: stock/templates/stock/location.html:29 templates/InvenTree/search.html:155
-#: templates/InvenTree/settings/tabs.html:25 templates/js/part.js:192
-#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:22
+#: templates/InvenTree/settings/tabs.html:28 templates/js/part.js:192
+#: templates/js/part.js:418 templates/js/stock.js:520 templates/navbar.html:26
msgid "Stock"
msgstr ""
@@ -1778,21 +1857,21 @@ msgstr ""
#: order/templates/order/receive_parts.html:14 part/models.py:321
#: part/templates/part/cat_link.html:7 part/templates/part/category.html:94
#: part/templates/part/category_tabs.html:6
-#: templates/InvenTree/settings/tabs.html:22 templates/navbar.html:19
+#: templates/InvenTree/settings/tabs.html:25 templates/navbar.html:23
#: templates/stats.html:35 templates/stats.html:44 users/models.py:33
msgid "Parts"
msgstr ""
#: company/views.py:55 part/templates/part/tabs.html:42
-#: templates/navbar.html:31
+#: templates/navbar.html:35
msgid "Suppliers"
msgstr ""
-#: company/views.py:62 templates/navbar.html:32
+#: company/views.py:62 templates/navbar.html:36
msgid "Manufacturers"
msgstr ""
-#: company/views.py:69 templates/navbar.html:41
+#: company/views.py:69 templates/navbar.html:45
msgid "Customers"
msgstr ""
@@ -1868,47 +1947,47 @@ msgstr ""
msgid "Delete Price Break"
msgstr ""
-#: label/api.py:171 report/api.py:161
+#: label/api.py:179
msgid "Must provide valid StockItem(s)"
msgstr ""
-#: label/api.py:185 label/api.py:337
+#: label/api.py:193 label/api.py:353
msgid "Error during label rendering"
msgstr ""
-#: label/api.py:324
+#: label/api.py:340
msgid "Must provide valid StockLocation(s)"
msgstr ""
-#: label/models.py:69
+#: label/models.py:70
msgid "Label name"
msgstr ""
-#: label/models.py:76
+#: label/models.py:77
msgid "Label description"
msgstr ""
-#: label/models.py:83 stock/forms.py:200
+#: label/models.py:84 stock/forms.py:200
msgid "Label"
msgstr ""
-#: label/models.py:84
+#: label/models.py:85
msgid "Label template file"
msgstr ""
-#: label/models.py:90 report/models.py:172
+#: label/models.py:91 report/models.py:257
msgid "Enabled"
msgstr ""
-#: label/models.py:91
+#: label/models.py:92
msgid "Label template is enabled"
msgstr ""
-#: label/models.py:137 label/models.py:190
+#: label/models.py:138 label/models.py:194
msgid "Query filters (comma-separated list of key=value pairs"
msgstr ""
-#: label/models.py:138 label/models.py:191 report/models.py:194
+#: label/models.py:139 label/models.py:195 report/models.py:277
msgid "Filters"
msgstr ""
@@ -2004,7 +2083,7 @@ msgid "Date order was completed"
msgstr ""
#: order/models.py:230 order/models.py:329 part/views.py:1506
-#: stock/models.py:265 stock/models.py:881
+#: stock/models.py:268 stock/models.py:884
msgid "Quantity must be greater than zero"
msgstr ""
@@ -2016,6 +2095,10 @@ msgstr ""
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr ""
+#: order/models.py:346
+msgid "Received items"
+msgstr ""
+
#: order/models.py:427
msgid "Company to which the items are being sold"
msgstr ""
@@ -2042,7 +2125,7 @@ msgstr ""
#: order/models.py:608 order/templates/order/order_base.html:9
#: order/templates/order/order_base.html:24
-#: stock/templates/stock/item_base.html:300 templates/js/order.js:145
+#: stock/templates/stock/item_base.html:296 templates/js/order.js:145
msgid "Purchase Order"
msgstr ""
@@ -2054,8 +2137,8 @@ msgstr ""
msgid "Number of items received"
msgstr ""
-#: order/models.py:631 stock/models.py:494
-#: stock/templates/stock/item_base.html:307
+#: order/models.py:631 stock/models.py:497
+#: stock/templates/stock/item_base.html:303
msgid "Purchase Price"
msgstr ""
@@ -2124,6 +2207,7 @@ msgid "Supplier Reference"
msgstr ""
#: order/templates/order/order_base.html:114
+#: report/templates/report/inventree_build_order_base.html:124
msgid "Issued"
msgstr ""
@@ -2258,7 +2342,7 @@ msgid "Select parts to receive against this order"
msgstr ""
#: order/templates/order/receive_parts.html:21
-#: part/templates/part/part_base.html:148 templates/js/part.js:434
+#: part/templates/part/part_base.html:147 templates/js/part.js:434
msgid "On Order"
msgstr ""
@@ -2298,24 +2382,26 @@ msgid "Sales Order Items"
msgstr ""
#: order/templates/order/sales_order_detail.html:72
-#: order/templates/order/sales_order_detail.html:154 stock/models.py:406
-#: stock/templates/stock/item_base.html:232 templates/js/build.js:418
+#: order/templates/order/sales_order_detail.html:154
+#: report/templates/report/inventree_test_report_base.html:75
+#: stock/models.py:409 stock/templates/stock/item_base.html:228
+#: templates/js/build.js:418
msgid "Serial Number"
msgstr ""
#: order/templates/order/sales_order_detail.html:96 templates/js/build.js:459
-#: templates/js/build.js:769
+#: templates/js/build.js:782
msgid "Edit stock allocation"
msgstr ""
#: order/templates/order/sales_order_detail.html:97 templates/js/build.js:461
-#: templates/js/build.js:770
+#: templates/js/build.js:783
msgid "Delete stock allocation"
msgstr ""
#: order/templates/order/sales_order_detail.html:225
#: part/templates/part/tabs.html:23 templates/js/build.js:523
-#: templates/js/build.js:765
+#: templates/js/build.js:778
msgid "Allocated"
msgstr ""
@@ -2514,7 +2600,7 @@ msgstr ""
msgid "Default Location"
msgstr ""
-#: part/bom.py:139 part/templates/part/part_base.html:121
+#: part/bom.py:139 part/templates/part/part_base.html:120
msgid "Available Stock"
msgstr ""
@@ -2738,7 +2824,7 @@ msgid "Part category"
msgstr ""
#: part/models.py:698 part/templates/part/detail.html:25
-#: part/templates/part/part_base.html:98 templates/js/part.js:180
+#: part/templates/part/part_base.html:97 templates/js/part.js:180
msgid "IPN"
msgstr ""
@@ -2750,7 +2836,7 @@ msgstr ""
msgid "Part revision or version number"
msgstr ""
-#: part/models.py:706 part/templates/part/detail.html:32
+#: part/models.py:706 part/templates/part/detail.html:32 report/models.py:181
#: templates/js/part.js:184
msgid "Revision"
msgstr ""
@@ -2775,7 +2861,7 @@ msgstr ""
msgid "Expiry time (in days) for stock items of this part"
msgstr ""
-#: part/models.py:788 part/templates/part/detail.html:108
+#: part/models.py:788 part/templates/part/detail.html:110
msgid "Minimum Stock"
msgstr ""
@@ -2783,7 +2869,7 @@ msgstr ""
msgid "Minimum allowed stock level"
msgstr ""
-#: part/models.py:795 part/templates/part/detail.html:102
+#: part/models.py:795 part/templates/part/detail.html:103
#: part/templates/part/params.html:26
msgid "Units"
msgstr ""
@@ -2812,7 +2898,7 @@ msgstr ""
msgid "Can this part be sold to customers?"
msgstr ""
-#: part/models.py:828 part/templates/part/detail.html:222
+#: part/models.py:828 part/templates/part/detail.html:224
#: templates/js/table_filters.js:19 templates/js/table_filters.js:55
#: templates/js/table_filters.js:196 templates/js/table_filters.js:265
msgid "Active"
@@ -2941,7 +3027,7 @@ msgid "BOM line checksum"
msgstr ""
#: part/models.py:1967 part/views.py:1512 part/views.py:1564
-#: stock/models.py:255
+#: stock/models.py:258
msgid "Quantity must be integer value for trackable parts"
msgstr ""
@@ -2978,8 +3064,8 @@ msgstr ""
#: part/templates/part/allocation.html:45
#: stock/templates/stock/item_base.html:8
#: stock/templates/stock/item_base.html:89
-#: stock/templates/stock/item_base.html:315
-#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:751
+#: stock/templates/stock/item_base.html:311
+#: stock/templates/stock/stock_adjust.html:16 templates/js/build.js:764
#: templates/js/stock.js:880 templates/js/stock.js:1140
msgid "Stock Item"
msgstr ""
@@ -3008,64 +3094,43 @@ msgstr ""
msgid "Import BOM data"
msgstr ""
-#: part/templates/part/bom.html:38
-msgid "Import from File"
-msgstr ""
-
#: part/templates/part/bom.html:41
msgid "Copy BOM from parent part"
msgstr ""
-#: part/templates/part/bom.html:42
-msgid "Copy from Parent"
-msgstr ""
-
#: part/templates/part/bom.html:45
msgid "New BOM Item"
msgstr ""
-#: part/templates/part/bom.html:46
-msgid "Add Item"
-msgstr ""
-
#: part/templates/part/bom.html:48
msgid "Finish Editing"
msgstr ""
-#: part/templates/part/bom.html:49
-msgid "Finished"
-msgstr ""
-
#: part/templates/part/bom.html:53
msgid "Edit BOM"
msgstr ""
-#: part/templates/part/bom.html:54 part/templates/part/params.html:38
-#: templates/InvenTree/settings/user.html:19
-msgid "Edit"
-msgstr ""
-
#: part/templates/part/bom.html:57
msgid "Validate Bill of Materials"
msgstr ""
-#: part/templates/part/bom.html:58
-msgid "Validate"
-msgstr ""
-
-#: part/templates/part/bom.html:62 part/views.py:1803
+#: part/templates/part/bom.html:63 part/views.py:1803
msgid "Export Bill of Materials"
msgstr ""
-#: part/templates/part/bom.html:123
+#: part/templates/part/bom.html:66
+msgid "Print BOM Report"
+msgstr ""
+
+#: part/templates/part/bom.html:126
msgid "Delete selected BOM items?"
msgstr ""
-#: part/templates/part/bom.html:124
+#: part/templates/part/bom.html:127
msgid "All selected BOM items will be deleted"
msgstr ""
-#: part/templates/part/bom.html:183 part/views.py:594
+#: part/templates/part/bom.html:186 part/views.py:594
#: templates/js/stock.js:1036
msgid "Create New Part"
msgstr ""
@@ -3265,79 +3330,79 @@ msgstr ""
msgid "No serial numbers recorded"
msgstr ""
-#: part/templates/part/detail.html:115
+#: part/templates/part/detail.html:117
msgid "Stock Expiry Time"
msgstr ""
-#: part/templates/part/detail.html:121 templates/js/order.js:287
+#: part/templates/part/detail.html:123 templates/js/order.js:287
msgid "Creation Date"
msgstr ""
-#: part/templates/part/detail.html:127
+#: part/templates/part/detail.html:129
msgid "Created By"
msgstr ""
-#: part/templates/part/detail.html:134
+#: part/templates/part/detail.html:136
msgid "Responsible User"
msgstr ""
-#: part/templates/part/detail.html:148
+#: part/templates/part/detail.html:150
msgid "Part is virtual (not a physical part)"
msgstr ""
-#: part/templates/part/detail.html:150
+#: part/templates/part/detail.html:152
msgid "Part is not a virtual part"
msgstr ""
-#: part/templates/part/detail.html:158
+#: part/templates/part/detail.html:160
msgid "Part is a template part (variants can be made from this part)"
msgstr ""
-#: part/templates/part/detail.html:160
+#: part/templates/part/detail.html:162
msgid "Part is not a template part"
msgstr ""
-#: part/templates/part/detail.html:168
+#: part/templates/part/detail.html:170
msgid "Part can be assembled from other parts"
msgstr ""
-#: part/templates/part/detail.html:170
+#: part/templates/part/detail.html:172
msgid "Part cannot be assembled from other parts"
msgstr ""
-#: part/templates/part/detail.html:178
+#: part/templates/part/detail.html:180
msgid "Part can be used in assemblies"
msgstr ""
-#: part/templates/part/detail.html:180
+#: part/templates/part/detail.html:182
msgid "Part cannot be used in assemblies"
msgstr ""
-#: part/templates/part/detail.html:188
+#: part/templates/part/detail.html:190
msgid "Part stock is tracked by serial number"
msgstr ""
-#: part/templates/part/detail.html:190
+#: part/templates/part/detail.html:192
msgid "Part stock is not tracked by serial number"
msgstr ""
-#: part/templates/part/detail.html:198 part/templates/part/detail.html:200
+#: part/templates/part/detail.html:200 part/templates/part/detail.html:202
msgid "Part can be purchased from external suppliers"
msgstr ""
-#: part/templates/part/detail.html:208
+#: part/templates/part/detail.html:210
msgid "Part can be sold to customers"
msgstr ""
-#: part/templates/part/detail.html:210
+#: part/templates/part/detail.html:212
msgid "Part cannot be sold to customers"
msgstr ""
-#: part/templates/part/detail.html:225
+#: part/templates/part/detail.html:227
msgid "Part is active"
msgstr ""
-#: part/templates/part/detail.html:227
+#: part/templates/part/detail.html:229
msgid "Part is not active"
msgstr ""
@@ -3359,13 +3424,19 @@ msgstr ""
msgid "New Parameter"
msgstr ""
-#: part/templates/part/params.html:25 stock/models.py:1541
-#: templates/InvenTree/settings/header.html:8 templates/js/stock.js:124
+#: part/templates/part/params.html:25
+#: report/templates/report/inventree_test_report_base.html:90
+#: stock/models.py:1569 templates/InvenTree/settings/header.html:8
+#: templates/js/stock.js:124
msgid "Value"
msgstr ""
+#: part/templates/part/params.html:38 templates/InvenTree/settings/user.html:19
+msgid "Edit"
+msgstr ""
+
#: part/templates/part/params.html:41 part/templates/part/related.html:41
-#: part/templates/part/supplier.html:19 users/models.py:164
+#: part/templates/part/supplier.html:19 users/models.py:167
msgid "Delete"
msgstr ""
@@ -3394,65 +3465,65 @@ msgstr ""
msgid "Star this part"
msgstr ""
-#: part/templates/part/part_base.html:51
+#: part/templates/part/part_base.html:50
#: stock/templates/stock/item_base.html:127
-#: stock/templates/stock/location.html:45
+#: stock/templates/stock/location.html:44
msgid "Barcode actions"
msgstr ""
-#: part/templates/part/part_base.html:53
+#: part/templates/part/part_base.html:52
#: stock/templates/stock/item_base.html:129
-#: stock/templates/stock/location.html:47
+#: stock/templates/stock/location.html:46
msgid "Show QR Code"
msgstr ""
-#: part/templates/part/part_base.html:54
-#: stock/templates/stock/item_base.html:147
-#: stock/templates/stock/location.html:48
+#: part/templates/part/part_base.html:53
+#: stock/templates/stock/item_base.html:145
+#: stock/templates/stock/location.html:47
msgid "Print Label"
msgstr ""
-#: part/templates/part/part_base.html:59
+#: part/templates/part/part_base.html:58
msgid "Show pricing information"
msgstr ""
-#: part/templates/part/part_base.html:63
+#: part/templates/part/part_base.html:62
msgid "Count part stock"
msgstr ""
-#: part/templates/part/part_base.html:78
+#: part/templates/part/part_base.html:77
msgid "Part actions"
msgstr ""
-#: part/templates/part/part_base.html:81
+#: part/templates/part/part_base.html:80
msgid "Duplicate part"
msgstr ""
-#: part/templates/part/part_base.html:84
+#: part/templates/part/part_base.html:83
msgid "Edit part"
msgstr ""
-#: part/templates/part/part_base.html:87
+#: part/templates/part/part_base.html:86
msgid "Delete part"
msgstr ""
-#: part/templates/part/part_base.html:127 templates/js/table_filters.js:121
+#: part/templates/part/part_base.html:126 templates/js/table_filters.js:121
msgid "In Stock"
msgstr ""
-#: part/templates/part/part_base.html:134
+#: part/templates/part/part_base.html:133
msgid "Allocated to Build Orders"
msgstr ""
-#: part/templates/part/part_base.html:141
+#: part/templates/part/part_base.html:140
msgid "Allocated to Sales Orders"
msgstr ""
-#: part/templates/part/part_base.html:163 templates/js/bom.js:260
+#: part/templates/part/part_base.html:162 templates/js/bom.js:260
msgid "Can Build"
msgstr ""
-#: part/templates/part/part_base.html:169
+#: part/templates/part/part_base.html:168
msgid "Underway"
msgstr ""
@@ -3545,7 +3616,7 @@ msgstr ""
msgid "Used In"
msgstr ""
-#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:373
+#: part/templates/part/tabs.html:61 stock/templates/stock/item_base.html:369
msgid "Tests"
msgstr ""
@@ -3794,34 +3865,101 @@ msgstr ""
msgid "Confim BOM item deletion"
msgstr ""
-#: report/models.py:153
+#: report/api.py:151
+msgid "No valid objects provided to template"
+msgstr ""
+
+#: report/models.py:163
msgid "Template name"
msgstr ""
-#: report/models.py:160
+#: report/models.py:169
msgid "Report template file"
msgstr ""
-#: report/models.py:167
+#: report/models.py:176
msgid "Report template description"
msgstr ""
-#: report/models.py:173
+#: report/models.py:182
+msgid "Report revision number (auto-increments)"
+msgstr ""
+
+#: report/models.py:258
msgid "Report template is enabled"
msgstr ""
-#: report/models.py:195
-msgid "Part query filters (comma-separated list of key=value pairs)"
+#: report/models.py:278
+msgid "StockItem query filters (comma-separated list of key=value pairs)"
msgstr ""
-#: report/models.py:244
+#: report/models.py:324
+msgid "Build Filters"
+msgstr ""
+
+#: report/models.py:325
+msgid "Build query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:361
+msgid "Part Filters"
+msgstr ""
+
+#: report/models.py:362
+msgid "Part query filters (comma-separated list of key=value pairs"
+msgstr ""
+
+#: report/models.py:407
+msgid "Report snippet file"
+msgstr ""
+
+#: report/models.py:411
+msgid "Snippet file description"
+msgstr ""
+
+#: report/models.py:446
msgid "Report asset file"
msgstr ""
-#: report/models.py:247
+#: report/models.py:449
msgid "Asset file description"
msgstr ""
+#: report/templates/report/inventree_build_order_base.html:149
+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:83
+msgid "Test Results"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:88
+#: stock/models.py:1557
+msgid "Test"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:89
+#: stock/models.py:1563
+msgid "Result"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:92
+#: templates/js/order.js:193 templates/js/stock.js:862
+msgid "Date"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:103
+msgid "Pass"
+msgstr ""
+
+#: report/templates/report/inventree_test_report_base.html:105
+msgid "Fail"
+msgstr ""
+
#: stock/forms.py:117
msgid "Enter unique serial numbers (or leave blank)"
msgstr ""
@@ -3886,237 +4024,233 @@ msgstr ""
msgid "Set the destination as the default location for selected parts"
msgstr ""
-#: stock/models.py:200
+#: stock/models.py:203
msgid "Created stock item"
msgstr ""
-#: stock/models.py:236
+#: stock/models.py:239
msgid "StockItem with this serial number already exists"
msgstr ""
-#: stock/models.py:272
+#: stock/models.py:275
#, python-brace-format
msgid "Part type ('{pf}') must be {pe}"
msgstr ""
-#: stock/models.py:282 stock/models.py:291
+#: stock/models.py:285 stock/models.py:294
msgid "Quantity must be 1 for item with a serial number"
msgstr ""
-#: stock/models.py:283
+#: stock/models.py:286
msgid "Serial number cannot be set if quantity greater than 1"
msgstr ""
-#: stock/models.py:305
+#: stock/models.py:308
msgid "Item cannot belong to itself"
msgstr ""
-#: stock/models.py:311
+#: stock/models.py:314
msgid "Item must have a build reference if is_building=True"
msgstr ""
-#: stock/models.py:318
+#: stock/models.py:321
msgid "Build reference does not point to the same part object"
msgstr ""
-#: stock/models.py:358
+#: stock/models.py:361
msgid "Parent Stock Item"
msgstr ""
-#: stock/models.py:367
+#: stock/models.py:370
msgid "Base part"
msgstr ""
-#: stock/models.py:376
+#: stock/models.py:379
msgid "Select a matching supplier part for this stock item"
msgstr ""
-#: stock/models.py:381 stock/templates/stock/stock_app_base.html:7
+#: stock/models.py:384 stock/templates/stock/stock_app_base.html:7
msgid "Stock Location"
msgstr ""
-#: stock/models.py:384
+#: stock/models.py:387
msgid "Where is this stock item located?"
msgstr ""
-#: stock/models.py:389 stock/templates/stock/item_base.html:253
+#: stock/models.py:392 stock/templates/stock/item_base.html:249
msgid "Installed In"
msgstr ""
-#: stock/models.py:392
+#: stock/models.py:395
msgid "Is this item installed in another item?"
msgstr ""
-#: stock/models.py:408
+#: stock/models.py:411
msgid "Serial number for this item"
msgstr ""
-#: stock/models.py:420
+#: stock/models.py:423
msgid "Batch code for this stock item"
msgstr ""
-#: stock/models.py:424
+#: stock/models.py:427
msgid "Stock Quantity"
msgstr ""
-#: stock/models.py:433
+#: stock/models.py:436
msgid "Source Build"
msgstr ""
-#: stock/models.py:435
+#: stock/models.py:438
msgid "Build for this stock item"
msgstr ""
-#: stock/models.py:446
+#: stock/models.py:449
msgid "Source Purchase Order"
msgstr ""
-#: stock/models.py:449
+#: stock/models.py:452
msgid "Purchase order for this stock item"
msgstr ""
-#: stock/models.py:455
+#: stock/models.py:458
msgid "Destination Sales Order"
msgstr ""
-#: stock/models.py:461 stock/templates/stock/item_base.html:340
+#: stock/models.py:464 stock/templates/stock/item_base.html:336
#: templates/js/stock.js:613
msgid "Expiry Date"
msgstr ""
-#: stock/models.py:462
+#: stock/models.py:465
msgid ""
"Expiry date for stock item. Stock will be considered expired after this date"
msgstr ""
-#: stock/models.py:475
+#: stock/models.py:478
msgid "Delete this Stock Item when stock is depleted"
msgstr ""
-#: stock/models.py:485 stock/templates/stock/item_notes.html:14
+#: stock/models.py:488 stock/templates/stock/item_notes.html:14
#: stock/templates/stock/item_notes.html:30
msgid "Stock Item Notes"
msgstr ""
-#: stock/models.py:495
+#: stock/models.py:498
msgid "Single unit purchase price at time of purchase"
msgstr ""
-#: stock/models.py:599
+#: stock/models.py:602
msgid "Assigned to Customer"
msgstr ""
-#: stock/models.py:601
+#: stock/models.py:604
msgid "Manually assigned to customer"
msgstr ""
-#: stock/models.py:614
+#: stock/models.py:617
msgid "Returned from customer"
msgstr ""
-#: stock/models.py:616
+#: stock/models.py:619
msgid "Returned to location"
msgstr ""
-#: stock/models.py:741
+#: stock/models.py:744
msgid "Installed into stock item"
msgstr ""
-#: stock/models.py:749
+#: stock/models.py:752
msgid "Installed stock item"
msgstr ""
-#: stock/models.py:773
+#: stock/models.py:776
msgid "Uninstalled stock item"
msgstr ""
-#: stock/models.py:792
+#: stock/models.py:795
msgid "Uninstalled into location"
msgstr ""
-#: stock/models.py:872
+#: stock/models.py:875
msgid "Part is not set as trackable"
msgstr ""
-#: stock/models.py:878
+#: stock/models.py:881
msgid "Quantity must be integer"
msgstr ""
-#: stock/models.py:884
+#: stock/models.py:887
#, python-brace-format
msgid "Quantity must not exceed available stock quantity ({n})"
msgstr ""
-#: stock/models.py:887
+#: stock/models.py:890
msgid "Serial numbers must be a list of integers"
msgstr ""
-#: stock/models.py:890
+#: stock/models.py:893
msgid "Quantity does not match serial numbers"
msgstr ""
-#: stock/models.py:922
+#: stock/models.py:925
msgid "Add serial number"
msgstr ""
-#: stock/models.py:925
+#: stock/models.py:928
#, python-brace-format
msgid "Serialized {n} items"
msgstr ""
-#: stock/models.py:1036
+#: stock/models.py:1006
+msgid "Split from existing stock"
+msgstr ""
+
+#: stock/models.py:1044
msgid "StockItem cannot be moved as it is not in stock"
msgstr ""
-#: stock/models.py:1442
+#: stock/models.py:1470
msgid "Tracking entry title"
msgstr ""
-#: stock/models.py:1444
+#: stock/models.py:1472
msgid "Entry notes"
msgstr ""
-#: stock/models.py:1446
+#: stock/models.py:1474
msgid "Link to external page for further information"
msgstr ""
-#: stock/models.py:1506
+#: stock/models.py:1534
msgid "Value must be provided for this test"
msgstr ""
-#: stock/models.py:1512
+#: stock/models.py:1540
msgid "Attachment must be uploaded for this test"
msgstr ""
-#: stock/models.py:1529
-msgid "Test"
-msgstr ""
-
-#: stock/models.py:1530
+#: stock/models.py:1558
msgid "Test name"
msgstr ""
-#: stock/models.py:1535
-msgid "Result"
-msgstr ""
-
-#: stock/models.py:1536 templates/js/table_filters.js:172
+#: stock/models.py:1564 templates/js/table_filters.js:172
msgid "Test result"
msgstr ""
-#: stock/models.py:1542
+#: stock/models.py:1570
msgid "Test output value"
msgstr ""
-#: stock/models.py:1548
+#: stock/models.py:1576
msgid "Attachment"
msgstr ""
-#: stock/models.py:1549
+#: stock/models.py:1577
msgid "Test result attachment"
msgstr ""
-#: stock/models.py:1555
+#: stock/models.py:1583
msgid "Test notes"
msgstr ""
@@ -4174,12 +4308,12 @@ msgid ""
msgstr ""
#: stock/templates/stock/item_base.html:91
-#: stock/templates/stock/item_base.html:344 templates/js/table_filters.js:111
+#: stock/templates/stock/item_base.html:340 templates/js/table_filters.js:111
msgid "Expired"
msgstr ""
#: stock/templates/stock/item_base.html:95
-#: stock/templates/stock/item_base.html:346 templates/js/table_filters.js:116
+#: stock/templates/stock/item_base.html:342 templates/js/table_filters.js:116
msgid "Stale"
msgstr ""
@@ -4196,115 +4330,115 @@ msgstr ""
msgid "Scan to Location"
msgstr ""
-#: stock/templates/stock/item_base.html:144
+#: stock/templates/stock/item_base.html:143
msgid "Printing actions"
msgstr ""
-#: stock/templates/stock/item_base.html:150
+#: stock/templates/stock/item_base.html:147
#: stock/templates/stock/item_tests.html:25
msgid "Test Report"
msgstr ""
-#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/item_base.html:156
msgid "Stock adjustment actions"
msgstr ""
-#: stock/templates/stock/item_base.html:164
-#: stock/templates/stock/location.html:60 templates/stock_table.html:53
+#: stock/templates/stock/item_base.html:160
+#: stock/templates/stock/location.html:59 templates/stock_table.html:55
msgid "Count stock"
msgstr ""
-#: stock/templates/stock/item_base.html:165 templates/stock_table.html:51
+#: stock/templates/stock/item_base.html:161 templates/stock_table.html:53
msgid "Add stock"
msgstr ""
-#: stock/templates/stock/item_base.html:166 templates/stock_table.html:52
+#: stock/templates/stock/item_base.html:162 templates/stock_table.html:54
msgid "Remove stock"
msgstr ""
-#: stock/templates/stock/item_base.html:168
+#: stock/templates/stock/item_base.html:164
msgid "Transfer stock"
msgstr ""
-#: stock/templates/stock/item_base.html:170
+#: stock/templates/stock/item_base.html:166
msgid "Serialize stock"
msgstr ""
-#: stock/templates/stock/item_base.html:174
+#: stock/templates/stock/item_base.html:170
msgid "Assign to customer"
msgstr ""
-#: stock/templates/stock/item_base.html:177
+#: stock/templates/stock/item_base.html:173
msgid "Return to stock"
msgstr ""
-#: stock/templates/stock/item_base.html:181 templates/js/stock.js:1177
+#: stock/templates/stock/item_base.html:177 templates/js/stock.js:1177
msgid "Uninstall stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:181
+#: stock/templates/stock/item_base.html:177
msgid "Uninstall"
msgstr ""
-#: stock/templates/stock/item_base.html:190
-#: stock/templates/stock/location.html:57
+#: stock/templates/stock/item_base.html:186
+#: stock/templates/stock/location.html:56
msgid "Stock actions"
msgstr ""
-#: stock/templates/stock/item_base.html:193
+#: stock/templates/stock/item_base.html:189
msgid "Convert to variant"
msgstr ""
-#: stock/templates/stock/item_base.html:196
+#: stock/templates/stock/item_base.html:192
msgid "Duplicate stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:198
+#: stock/templates/stock/item_base.html:194
msgid "Edit stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:201
+#: stock/templates/stock/item_base.html:197
msgid "Delete stock item"
msgstr ""
-#: stock/templates/stock/item_base.html:213
+#: stock/templates/stock/item_base.html:209
msgid "Stock Item Details"
msgstr ""
-#: stock/templates/stock/item_base.html:272 templates/js/build.js:442
+#: stock/templates/stock/item_base.html:268 templates/js/build.js:442
msgid "No location set"
msgstr ""
-#: stock/templates/stock/item_base.html:279
+#: stock/templates/stock/item_base.html:275
msgid "Barcode Identifier"
msgstr ""
-#: stock/templates/stock/item_base.html:293 templates/js/build.js:642
-#: templates/navbar.html:25
+#: stock/templates/stock/item_base.html:289 templates/js/build.js:648
+#: templates/navbar.html:29
msgid "Build"
msgstr ""
-#: stock/templates/stock/item_base.html:314
+#: stock/templates/stock/item_base.html:310
msgid "Parent Item"
msgstr ""
-#: stock/templates/stock/item_base.html:344
+#: stock/templates/stock/item_base.html:340
msgid "This StockItem expired on"
msgstr ""
-#: stock/templates/stock/item_base.html:346
+#: stock/templates/stock/item_base.html:342
msgid "This StockItem expires on"
msgstr ""
-#: stock/templates/stock/item_base.html:353 templates/js/stock.js:619
+#: stock/templates/stock/item_base.html:349 templates/js/stock.js:619
msgid "Last Updated"
msgstr ""
-#: stock/templates/stock/item_base.html:358
+#: stock/templates/stock/item_base.html:354
msgid "Last Stocktake"
msgstr ""
-#: stock/templates/stock/item_base.html:362
+#: stock/templates/stock/item_base.html:358
msgid "No stocktake performed"
msgstr ""
@@ -4370,50 +4504,50 @@ msgstr ""
msgid "All stock items"
msgstr ""
-#: stock/templates/stock/location.html:49
+#: stock/templates/stock/location.html:48
msgid "Check-in Items"
msgstr ""
-#: stock/templates/stock/location.html:66
+#: stock/templates/stock/location.html:65
msgid "Location actions"
msgstr ""
-#: stock/templates/stock/location.html:68
+#: stock/templates/stock/location.html:67
msgid "Edit location"
msgstr ""
-#: stock/templates/stock/location.html:70
+#: stock/templates/stock/location.html:69
msgid "Delete location"
msgstr ""
-#: stock/templates/stock/location.html:81
+#: stock/templates/stock/location.html:80
msgid "Location Details"
msgstr ""
-#: stock/templates/stock/location.html:86
+#: stock/templates/stock/location.html:85
msgid "Location Path"
msgstr ""
-#: stock/templates/stock/location.html:91
+#: stock/templates/stock/location.html:90
msgid "Location Description"
msgstr ""
-#: stock/templates/stock/location.html:96
+#: stock/templates/stock/location.html:95
msgid "Sublocations"
msgstr ""
-#: stock/templates/stock/location.html:101
-#: stock/templates/stock/location.html:116
+#: stock/templates/stock/location.html:100
+#: stock/templates/stock/location.html:115
#: templates/InvenTree/search_stock_items.html:6 templates/stats.html:48
#: templates/stats.html:57 users/models.py:35
msgid "Stock Items"
msgstr ""
-#: stock/templates/stock/location.html:106
+#: stock/templates/stock/location.html:105
msgid "Stock Details"
msgstr ""
-#: stock/templates/stock/location.html:111
+#: stock/templates/stock/location.html:110
#: templates/InvenTree/search_stock_location.html:6 templates/stats.html:52
#: users/models.py:34
msgid "Stock Locations"
@@ -4581,14 +4715,8 @@ msgstr ""
msgid "Quantity must not exceed {x}"
msgstr ""
-#: stock/views.py:1132
-#, python-brace-format
-msgid "Added stock to {n} items"
-msgstr ""
-
-#: stock/views.py:1147
-#, python-brace-format
-msgid "Removed stock from {n} items"
+#: stock/views.py:1117
+msgid "No action performed"
msgstr ""
#: stock/views.py:1160
@@ -4760,7 +4888,7 @@ msgstr ""
msgid "Global InvenTree Settings"
msgstr ""
-#: templates/InvenTree/settings/global.html:24
+#: templates/InvenTree/settings/global.html:25
msgid "Barcode Settings"
msgstr ""
@@ -4788,6 +4916,10 @@ msgstr ""
msgid "Purchase Order Settings"
msgstr ""
+#: templates/InvenTree/settings/report.html:10
+msgid "Report Settings"
+msgstr ""
+
#: templates/InvenTree/settings/setting.html:23
msgid "No value set"
msgstr ""
@@ -4797,7 +4929,7 @@ msgid "Edit setting"
msgstr ""
#: templates/InvenTree/settings/settings.html:7
-#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:66
+#: templates/InvenTree/settings/settings.html:13 templates/navbar.html:76
msgid "Settings"
msgstr ""
@@ -4809,7 +4941,7 @@ msgstr ""
msgid "Stock Settings"
msgstr ""
-#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:46
+#: templates/InvenTree/settings/stock.html:13 templates/stock_table.html:48
msgid "Stock Options"
msgstr ""
@@ -4835,6 +4967,10 @@ msgid "Global"
msgstr ""
#: templates/InvenTree/settings/tabs.html:19
+msgid "Report"
+msgstr ""
+
+#: templates/InvenTree/settings/tabs.html:22
msgid "Categories"
msgstr ""
@@ -4865,6 +5001,7 @@ msgid "Change Password"
msgstr ""
#: templates/InvenTree/settings/user.html:28
+#: templates/registration/login.html:58
msgid "Username"
msgstr ""
@@ -5121,7 +5258,7 @@ msgstr ""
msgid "Build stock"
msgstr ""
-#: templates/js/build.js:582 templates/stock_table.html:55
+#: templates/js/build.js:582 templates/stock_table.html:57
msgid "Order stock"
msgstr ""
@@ -5133,11 +5270,16 @@ msgstr ""
msgid "No builds matching query"
msgstr ""
-#: templates/js/build.js:656
+#: templates/js/build.js:642 templates/js/part.js:343 templates/js/stock.js:474
+#: templates/js/stock.js:1209
+msgid "Select"
+msgstr ""
+
+#: templates/js/build.js:662
msgid "Build order is overdue"
msgstr ""
-#: templates/js/build.js:747
+#: templates/js/build.js:760
msgid "No parts allocated for"
msgstr ""
@@ -5165,7 +5307,7 @@ msgstr ""
msgid "Assembled part"
msgstr ""
-#: templates/js/label.js:10 templates/js/report.js:89
+#: templates/js/label.js:10 templates/js/report.js:98
msgid "Select Stock Items"
msgstr ""
@@ -5193,11 +5335,11 @@ msgstr ""
msgid "No labels found which match selected stock location(s)"
msgstr ""
-#: templates/js/label.js:142 templates/js/report.js:38
+#: templates/js/label.js:142
msgid "stock items selected"
msgstr ""
-#: templates/js/label.js:150 templates/js/report.js:46
+#: templates/js/label.js:150
msgid "Select Label"
msgstr ""
@@ -5209,11 +5351,11 @@ msgstr ""
msgid "Show Error Information"
msgstr ""
-#: templates/js/modals.js:473
+#: templates/js/modals.js:473 templates/modals.html:64
msgid "Accept"
msgstr ""
-#: templates/js/modals.js:474
+#: templates/js/modals.js:474 templates/modals.html:63
msgid "Cancel"
msgstr ""
@@ -5222,12 +5364,12 @@ msgid "Loading Data"
msgstr ""
#: templates/js/modals.js:549 templates/js/modals.js:807
-#: templates/modals.html:19 templates/modals.html:41
+#: templates/modals.html:22 templates/modals.html:44
msgid "Submit"
msgstr ""
#: templates/js/modals.js:550 templates/js/modals.js:808
-#: templates/modals.html:18 templates/modals.html:40
+#: templates/modals.html:21 templates/modals.html:43 templates/modals.html:82
msgid "Close"
msgstr ""
@@ -5307,10 +5449,6 @@ msgstr ""
msgid "Order is overdue"
msgstr ""
-#: templates/js/order.js:193 templates/js/stock.js:862
-msgid "Date"
-msgstr ""
-
#: templates/js/order.js:229
msgid "No sales orders found"
msgstr ""
@@ -5343,11 +5481,6 @@ msgstr ""
msgid "No parts found"
msgstr ""
-#: templates/js/part.js:343 templates/js/stock.js:474
-#: templates/js/stock.js:1209
-msgid "Select"
-msgstr ""
-
#: templates/js/part.js:411
msgid "No category"
msgstr ""
@@ -5384,22 +5517,55 @@ msgstr ""
msgid "This test is defined for a parent part"
msgstr ""
-#: templates/js/report.js:61
+#: templates/js/report.js:47
+msgid "items selected"
+msgstr ""
+
+#: templates/js/report.js:55
+msgid "Select Report Template"
+msgstr ""
+
+#: templates/js/report.js:70
msgid "Select Test Report Template"
msgstr ""
-#: templates/js/report.js:90
+#: templates/js/report.js:99
msgid "Stock item(s) must be selected before printing reports"
msgstr ""
-#: templates/js/report.js:107
+#: templates/js/report.js:116 templates/js/report.js:169
+#: templates/js/report.js:223
msgid "No Reports Found"
msgstr ""
-#: templates/js/report.js:108
+#: templates/js/report.js:117
msgid "No report templates found which match selected stock item(s)"
msgstr ""
+#: templates/js/report.js:152
+msgid "Select Builds"
+msgstr ""
+
+#: templates/js/report.js:153
+msgid "Build(s) must be selected before printing reports"
+msgstr ""
+
+#: templates/js/report.js:170
+msgid "No report templates found which match selected build(s)"
+msgstr ""
+
+#: templates/js/report.js:205
+msgid "Select Parts"
+msgstr ""
+
+#: templates/js/report.js:206
+msgid "Part(s) must be selected before printing reports"
+msgstr ""
+
+#: templates/js/report.js:224
+msgid "No report templates found which match selected part(s)"
+msgstr ""
+
#: templates/js/stock.js:38
msgid "PASS"
msgstr ""
@@ -5673,95 +5839,111 @@ msgstr ""
msgid "Purchasable"
msgstr ""
-#: templates/js/tables.js:276
+#: templates/js/tables.js:268
msgid "Loading data"
msgstr ""
-#: templates/js/tables.js:279
+#: templates/js/tables.js:271
msgid "rows per page"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "Showing"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "to"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "of"
msgstr ""
-#: templates/js/tables.js:282
+#: templates/js/tables.js:274
msgid "rows"
msgstr ""
-#: templates/js/tables.js:285 templates/search_form.html:6
+#: templates/js/tables.js:277 templates/search_form.html:6
#: templates/search_form.html:8
msgid "Search"
msgstr ""
-#: templates/js/tables.js:288
+#: templates/js/tables.js:280
msgid "No matching results"
msgstr ""
-#: templates/js/tables.js:291
+#: templates/js/tables.js:283
msgid "Hide/Show pagination"
msgstr ""
-#: templates/js/tables.js:294
+#: templates/js/tables.js:286
msgid "Refresh"
msgstr ""
-#: templates/js/tables.js:297
+#: templates/js/tables.js:289
msgid "Toggle"
msgstr ""
-#: templates/js/tables.js:300
+#: templates/js/tables.js:292
msgid "Columns"
msgstr ""
-#: templates/js/tables.js:303
+#: templates/js/tables.js:295
msgid "All"
msgstr ""
-#: templates/modals.html:13 templates/modals.html:35
+#: templates/modals.html:14 templates/modals.html:38
msgid "Form errors exist"
msgstr ""
-#: templates/navbar.html:29
+#: templates/navbar.html:33
msgid "Buy"
msgstr ""
-#: templates/navbar.html:39
+#: templates/navbar.html:43
msgid "Sell"
msgstr ""
-#: templates/navbar.html:50
+#: templates/navbar.html:55
msgid "Scan Barcode"
msgstr ""
-#: templates/navbar.html:57
+#: templates/navbar.html:63
msgid "InvenTree server issues detected"
msgstr ""
-#: templates/navbar.html:63 users/models.py:31
+#: templates/navbar.html:69 users/models.py:31
msgid "Admin"
msgstr ""
-#: templates/navbar.html:67
+#: templates/navbar.html:71
msgid "Logout"
msgstr ""
-#: templates/navbar.html:69 templates/registration/login.html:43
+#: templates/navbar.html:73 templates/registration/login.html:89
msgid "Login"
msgstr ""
-#: templates/navbar.html:80
+#: templates/navbar.html:85
msgid "About InvenTree"
msgstr ""
+#: templates/registration/login.html:64
+msgid "Enter username"
+msgstr ""
+
+#: templates/registration/login.html:70
+msgid "Password"
+msgstr ""
+
+#: templates/registration/login.html:76
+msgid "Enter password"
+msgstr ""
+
+#: templates/registration/login.html:83
+msgid "Username / password combination is incorrect"
+msgstr ""
+
#: templates/stats.html:9
msgid "Server"
msgstr ""
@@ -5798,47 +5980,47 @@ msgstr ""
msgid "Print labels"
msgstr ""
-#: templates/stock_table.html:41
+#: templates/stock_table.html:42
msgid "Print test reports"
msgstr ""
-#: templates/stock_table.html:51
+#: templates/stock_table.html:53
msgid "Add to selected stock items"
msgstr ""
-#: templates/stock_table.html:52
+#: templates/stock_table.html:54
msgid "Remove from selected stock items"
msgstr ""
-#: templates/stock_table.html:53
+#: templates/stock_table.html:55
msgid "Stocktake selected stock items"
msgstr ""
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
msgid "Move selected stock items"
msgstr ""
-#: templates/stock_table.html:54
+#: templates/stock_table.html:56
msgid "Move stock"
msgstr ""
-#: templates/stock_table.html:55
+#: templates/stock_table.html:57
msgid "Order selected items"
msgstr ""
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
msgid "Change status"
msgstr ""
-#: templates/stock_table.html:56
+#: templates/stock_table.html:58
msgid "Change stock status"
msgstr ""
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
msgid "Delete selected items"
msgstr ""
-#: templates/stock_table.html:59
+#: templates/stock_table.html:61
msgid "Delete Stock"
msgstr ""
@@ -5866,38 +6048,38 @@ msgstr ""
msgid "Important dates"
msgstr ""
-#: users/models.py:147
+#: users/models.py:150
msgid "Permission set"
msgstr ""
-#: users/models.py:155
+#: users/models.py:158
msgid "Group"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "View"
msgstr ""
-#: users/models.py:158
+#: users/models.py:161
msgid "Permission to view items"
msgstr ""
-#: users/models.py:160
+#: users/models.py:163
msgid "Add"
msgstr ""
-#: users/models.py:160
+#: users/models.py:163
msgid "Permission to add items"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Change"
msgstr ""
-#: users/models.py:162
+#: users/models.py:165
msgid "Permissions to edit items"
msgstr ""
-#: users/models.py:164
+#: users/models.py:167
msgid "Permission to delete items"
msgstr ""
diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py
index 3c848620d5..1fd5092f14 100644
--- a/InvenTree/part/api.py
+++ b/InvenTree/part/api.py
@@ -810,11 +810,35 @@ class BomList(generics.ListCreateAPIView):
queryset = queryset.filter(optional=optional)
+ # Filter by "inherited" status
+ inherited = params.get('inherited', None)
+
+ if inherited is not None:
+ inherited = str2bool(inherited)
+
+ queryset = queryset.filter(inherited=inherited)
+
# Filter by part?
part = params.get('part', None)
if part is not None:
- queryset = queryset.filter(part=part)
+ """
+ If we are filtering by "part", there are two cases to consider:
+
+ a) Bom items which are defined for *this* part
+ b) Inherited parts which are defined for a *parent* part
+
+ So we need to construct two queries!
+ """
+
+ # First, check that the part is actually valid!
+ try:
+ part = Part.objects.get(pk=part)
+
+ queryset = queryset.filter(part.get_bom_item_filter())
+
+ except (ValueError, Part.DoesNotExist):
+ pass
# Filter by sub-part?
sub_part = params.get('sub_part', None)
diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py
index 16518937ae..85a851e235 100644
--- a/InvenTree/part/forms.py
+++ b/InvenTree/part/forms.py
@@ -331,6 +331,7 @@ class EditBomItemForm(HelperForm):
'reference',
'overage',
'note',
+ 'inherited',
'optional',
]
diff --git a/InvenTree/part/migrations/0063_bomitem_inherited.py b/InvenTree/part/migrations/0063_bomitem_inherited.py
new file mode 100644
index 0000000000..569236fd72
--- /dev/null
+++ b/InvenTree/part/migrations/0063_bomitem_inherited.py
@@ -0,0 +1,18 @@
+# Generated by Django 3.0.7 on 2021-02-17 10:51
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('part', '0062_merge_20210105_0056'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='bomitem',
+ name='inherited',
+ field=models.BooleanField(default=False, help_text='This BOM item is inherited by BOMs for variant parts', verbose_name='Inherited'),
+ ),
+ ]
diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py
index 8ba7ba799d..911a2cdac4 100644
--- a/InvenTree/part/models.py
+++ b/InvenTree/part/models.py
@@ -14,7 +14,7 @@ from django.urls import reverse
from django.db import models, transaction
from django.db.utils import IntegrityError
-from django.db.models import Sum, UniqueConstraint
+from django.db.models import Q, Sum, UniqueConstraint
from django.db.models.functions import Coalesce
from django.core.validators import MinValueValidator
@@ -41,7 +41,7 @@ from InvenTree.models import InvenTreeTree, InvenTreeAttachment
from InvenTree.fields import InvenTreeURLField
from InvenTree.helpers import decimal2string, normalize
-from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus
+from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus
from build import models as BuildModels
from order import models as OrderModels
@@ -418,8 +418,10 @@ class Part(MPTTModel):
p2=str(parent)
))})
+ bom_items = self.get_bom_items()
+
# Ensure that the parent part does not appear under any child BOM item!
- for item in self.bom_items.all():
+ for item in bom_items.all():
# Check for simple match
if item.sub_part == parent:
@@ -884,20 +886,135 @@ class Part(MPTTModel):
return max(total, 0)
+ def requiring_build_orders(self):
+ """
+ Return list of outstanding build orders which require this part
+ """
+
+ # List of BOM that this part is required for
+ boms = BomItem.objects.filter(sub_part=self)
+
+ part_ids = [bom.part.pk for bom in boms]
+
+ # Now, get a list of outstanding build orders which require this part
+ builds = BuildModels.Build.objects.filter(
+ part__in=part_ids,
+ status__in=BuildStatus.ACTIVE_CODES
+ )
+
+ return builds
+
+ def required_build_order_quantity(self):
+ """
+ Return the quantity of this part required for active build orders
+ """
+
+ # List of BOM that this part is required for
+ boms = BomItem.objects.filter(sub_part=self)
+
+ part_ids = [bom.part.pk for bom in boms]
+
+ # Now, get a list of outstanding build orders which require this part
+ builds = BuildModels.Build.objects.filter(
+ part__in=part_ids,
+ status__in=BuildStatus.ACTIVE_CODES
+ )
+
+ quantity = 0
+
+ for build in builds:
+
+ bom_item = None
+
+ # Match BOM item to build
+ for bom in boms:
+ if bom.part == build.part:
+ bom_item = bom
+ break
+
+ if bom_item is None:
+ logger.warning("Found null BomItem when calculating required quantity")
+ continue
+
+ build_quantity = build.quantity * bom_item.quantity
+
+ quantity += build_quantity
+
+ return quantity
+
+ def requiring_sales_orders(self):
+ """
+ Return a list of sales orders which require this part
+ """
+
+ orders = set()
+
+ # Get a list of line items for open orders which match this part
+ open_lines = OrderModels.SalesOrderLineItem.objects.filter(
+ order__status__in=SalesOrderStatus.OPEN,
+ part=self
+ )
+
+ for line in open_lines:
+ orders.add(line.order)
+
+ return orders
+
+ def required_sales_order_quantity(self):
+ """
+ Return the quantity of this part required for active sales orders
+ """
+
+ # Get a list of line items for open orders which match this part
+ open_lines = OrderModels.SalesOrderLineItem.objects.filter(
+ order__status__in=SalesOrderStatus.OPEN,
+ part=self
+ )
+
+ quantity = 0
+
+ for line in open_lines:
+ quantity += line.quantity
+
+ return quantity
+
+ def required_order_quantity(self):
+ """
+ Return total required to fulfil orders
+ """
+
+ return self.required_build_order_quantity() + self.required_sales_order_quantity()
+
@property
def quantity_to_order(self):
- """ Return the quantity needing to be ordered for this part. """
+ """
+ Return the quantity needing to be ordered for this part.
+
+ Here, an "order" could be one of:
+ - Build Order
+ - Sales Order
- # How many do we need to have "on hand" at any point?
- required = self.net_stock - self.minimum_stock
+ To work out how many we need to order:
- if required < 0:
- return abs(required)
+ Stock on hand = self.total_stock
+ Required for orders = self.required_order_quantity()
+ Currently on order = self.on_order
+ Currently building = self.quantity_being_built
+
+ """
- # Do not need to order any
- return 0
+ # Total requirement
+ required = self.required_order_quantity()
+
+ # Subtract stock levels
+ required -= max(self.total_stock, self.minimum_stock)
+
+ # Subtract quantity on order
+ required -= self.on_order
+
+ # Subtract quantity being built
+ required -= self.quantity_being_built
- required = self.net_stock
return max(required, 0)
@property
@@ -943,8 +1060,10 @@ class Part(MPTTModel):
total = None
+ bom_items = self.get_bom_items().prefetch_related('sub_part__stock_items')
+
# Calculate the minimum number of parts that can be built using each sub-part
- for item in self.bom_items.all().prefetch_related('sub_part__stock_items'):
+ for item in bom_items.all():
stock = item.sub_part.available_stock
# If (by some chance) we get here but the BOM item quantity is invalid,
@@ -979,16 +1098,22 @@ class Part(MPTTModel):
@property
def quantity_being_built(self):
- """ Return the current number of parts currently being built
+ """
+ Return the current number of parts currently being built.
+
+ Note: This is the total quantity of Build orders, *not* the number of build outputs.
+ In this fashion, it is the "projected" quantity of builds
"""
- stock_items = self.stock_items.filter(is_building=True)
+ builds = self.active_builds
- query = stock_items.aggregate(
- quantity=Coalesce(Sum('quantity'), Decimal(0))
- )
+ quantity = 0
- return query['quantity']
+ for build in builds:
+ # The remaining items in the build
+ quantity += build.remaining
+
+ return quantity
def build_order_allocations(self):
"""
@@ -1068,9 +1193,56 @@ class Part(MPTTModel):
return query['t']
+ def get_bom_item_filter(self, include_inherited=True):
+ """
+ Returns a query filter for all BOM items associated with this Part.
+
+ There are some considerations:
+
+ a) BOM items can be defined against *this* part
+ b) BOM items can be inherited from a *parent* part
+
+ We will construct a filter to grab *all* the BOM items!
+
+ Note: This does *not* return a queryset, it returns a Q object,
+ which can be used by some other query operation!
+ Because we want to keep our code DRY!
+
+ """
+
+ bom_filter = Q(part=self)
+
+ if include_inherited:
+ # We wish to include parent parts
+
+ parents = self.get_ancestors(include_self=False)
+
+ # There are parents available
+ if parents.count() > 0:
+ parent_ids = [p.pk for p in parents]
+
+ parent_filter = Q(
+ part__id__in=parent_ids,
+ inherited=True
+ )
+
+ # OR the filters together
+ bom_filter |= parent_filter
+
+ return bom_filter
+
+ def get_bom_items(self, include_inherited=True):
+ """
+ Return a queryset containing all BOM items for this part
+
+ By default, will include inherited BOM items
+ """
+
+ return BomItem.objects.filter(self.get_bom_item_filter(include_inherited=include_inherited))
+
@property
def has_bom(self):
- return self.bom_count > 0
+ return self.get_bom_items().count() > 0
@property
def has_trackable_parts(self):
@@ -1079,7 +1251,7 @@ class Part(MPTTModel):
This is important when building the part.
"""
- for bom_item in self.bom_items.all():
+ for bom_item in self.get_bom_items().all():
if bom_item.sub_part.trackable:
return True
@@ -1088,7 +1260,7 @@ class Part(MPTTModel):
@property
def bom_count(self):
""" Return the number of items contained in the BOM for this part """
- return self.bom_items.count()
+ return self.get_bom_items().count()
@property
def used_in_count(self):
@@ -1106,7 +1278,10 @@ class Part(MPTTModel):
hash = hashlib.md5(str(self.id).encode())
- for item in self.bom_items.all().prefetch_related('sub_part'):
+ # List *all* BOM items (including inherited ones!)
+ bom_items = self.get_bom_items().all().prefetch_related('sub_part')
+
+ for item in bom_items:
hash.update(str(item.get_item_hash()).encode())
return str(hash.digest())
@@ -1125,8 +1300,10 @@ class Part(MPTTModel):
- Saves the current date and the checking user
"""
- # Validate each line item too
- for item in self.bom_items.all():
+ # Validate each line item, ignoring inherited ones
+ bom_items = self.get_bom_items(include_inherited=False)
+
+ for item in bom_items.all():
item.validate_hash()
self.bom_checksum = self.get_bom_hash()
@@ -1137,7 +1314,10 @@ class Part(MPTTModel):
@transaction.atomic
def clear_bom(self):
- """ Clear the BOM items for the part (delete all BOM lines).
+ """
+ Clear the BOM items for the part (delete all BOM lines).
+
+ Note: Does *NOT* delete inherited BOM items!
"""
self.bom_items.all().delete()
@@ -1154,9 +1334,9 @@ class Part(MPTTModel):
if parts is None:
parts = set()
- items = BomItem.objects.filter(part=self.pk)
+ bom_items = self.get_bom_items().all()
- for bom_item in items:
+ for bom_item in bom_items:
sub_part = bom_item.sub_part
@@ -1204,7 +1384,7 @@ class Part(MPTTModel):
def has_complete_bom_pricing(self):
""" Return true if there is pricing information for each item in the BOM. """
- for item in self.bom_items.all().select_related('sub_part'):
+ for item in self.get_bom_items().all().select_related('sub_part'):
if not item.sub_part.has_pricing_info:
return False
@@ -1271,7 +1451,7 @@ class Part(MPTTModel):
min_price = None
max_price = None
- for item in self.bom_items.all().select_related('sub_part'):
+ for item in self.get_bom_items().all().select_related('sub_part'):
if item.sub_part.pk == self.pk:
print("Warning: Item contains itself in BOM")
@@ -1339,8 +1519,11 @@ class Part(MPTTModel):
if clear:
# Remove existing BOM items
+ # Note: Inherited BOM items are *not* deleted!
self.bom_items.all().delete()
+ # Copy existing BOM items from another part
+ # Note: Inherited BOM Items will *not* be duplicated!!
for bom_item in other.bom_items.all():
# If this part already has a BomItem pointing to the same sub-part,
# delete that BomItem from this part first!
@@ -1856,6 +2039,7 @@ class BomItem(models.Model):
overage: Estimated losses for a Build. Can be expressed as absolute value (e.g. '7') or a percentage (e.g. '2%')
note: Note field for this BOM item
checksum: Validation checksum for the particular BOM line item
+ inherited: This BomItem can be inherited by the BOMs of variant parts
"""
def save(self, *args, **kwargs):
@@ -1895,6 +2079,12 @@ class BomItem(models.Model):
checksum = models.CharField(max_length=128, blank=True, help_text=_('BOM line checksum'))
+ inherited = models.BooleanField(
+ default=False,
+ verbose_name=_('Inherited'),
+ help_text=_('This BOM item is inherited by BOMs for variant parts'),
+ )
+
def get_item_hash(self):
""" Calculate the checksum hash of this BOM line item:
diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py
index 05fc3091f7..103d0202f1 100644
--- a/InvenTree/part/serializers.py
+++ b/InvenTree/part/serializers.py
@@ -381,17 +381,18 @@ class BomItemSerializer(InvenTreeModelSerializer):
class Meta:
model = BomItem
fields = [
+ 'inherited',
+ 'note',
+ 'optional',
+ 'overage',
'pk',
'part',
'part_detail',
- 'sub_part',
- 'sub_part_detail',
'quantity',
'reference',
+ 'sub_part',
+ 'sub_part_detail',
# 'price_range',
- 'optional',
- 'overage',
- 'note',
'validated',
]
diff --git a/InvenTree/part/templates/part/bom.html b/InvenTree/part/templates/part/bom.html
index 515cae37a0..ca0446378c 100644
--- a/InvenTree/part/templates/part/bom.html
+++ b/InvenTree/part/templates/part/bom.html
@@ -35,45 +35,46 @@
{% if part.variant_of %}
{% endif %}
{% elif part.active %}
{% if roles.part.change %}
{% if part.is_bom_valid == False %}
{% endif %}
{% endif %}
+ {% endif %}
+
- {% endif %}
-
+
-
-
{% endblock %}
{% block js_load %}
@@ -215,4 +216,8 @@
{% endif %}
+ $("#print-bom-report").click(function() {
+ printBomReports([{{ part.pk }}]);
+ });
+
{% endblock %}
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index 59c33ea7b6..f5212d6312 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -97,11 +97,13 @@
{% endif %}
+ {% if part.units %}
|
{% trans "Units" %} |
{{ part.units }} |
+ {% endif %}
{% if part.minimum_stock > 0 %}
|
diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html
index f35d616a91..1221c271b6 100644
--- a/InvenTree/part/templates/part/part_base.html
+++ b/InvenTree/part/templates/part/part_base.html
@@ -119,36 +119,35 @@
{% trans "Available Stock" %}
|
- {% decimal part.available_stock %} {{ part.units }} |
+ {% decimal available %}{% if part.units %} {{ part.units }}{% endif %} |
|
{% trans "In Stock" %} |
{% include "part/stock_count.html" %} |
- {% if not part.is_template %}
- {% if part.build_order_allocation_count > 0 %}
-
- |
- {% trans "Allocated to Build Orders" %} |
- {% decimal part.build_order_allocation_count %} |
-
- {% endif %}
- {% if part.sales_order_allocation_count > 0 %}
-
- |
- {% trans "Allocated to Sales Orders" %} |
- {% decimal part.sales_order_allocation_count %} |
-
- {% endif %}
- {% if part.on_order > 0 %}
+ {% if on_order > 0 %}
|
{% trans "On Order" %} |
- {% decimal part.on_order %} |
+ {% decimal on_order %} |
{% endif %}
+ {% if required > 0 %}
+
+ |
+ {% trans "Required for Orders" %} |
+ {% decimal required %}
+ |
{% endif %}
+ {% if allocated > 0 %}
+
+ |
+ {% trans "Allocated to Orders" %} |
+ {% decimal allocated %} |
+
+ {% endif %}
+
{% if not part.is_template %}
{% if part.assembly %}
@@ -162,11 +161,11 @@
{% trans "Can Build" %} |
{% decimal part.can_build %} |
- {% if part.quantity_being_built > 0 %}
+ {% if quantity_being_built > 0 %}
|
- {% trans "Underway" %} |
- {% decimal part.quantity_being_built %} |
+ {% trans "Building" %} |
+ {% decimal quantity_being_built %} |
{% endif %}
{% endif %}
diff --git a/InvenTree/part/templates/part/stock_count.html b/InvenTree/part/templates/part/stock_count.html
index 58e447b051..5b70995a22 100644
--- a/InvenTree/part/templates/part/stock_count.html
+++ b/InvenTree/part/templates/part/stock_count.html
@@ -1,10 +1,10 @@
{% load inventree_extras %}
{% load i18n %}
-{% decimal part.total_stock %}
+{% decimal total_stock %}
-{% if part.total_stock == 0 %}
+{% if total_stock == 0 %}
{% trans "No Stock" %}
-{% elif part.total_stock < part.minimum_stock %}
+{% elif total_stock < part.minimum_stock %}
{% trans "Low Stock" %}
{% endif %}
\ No newline at end of file
diff --git a/InvenTree/part/templates/part/tabs.html b/InvenTree/part/templates/part/tabs.html
index 8bfaba4d89..32a62f94e9 100644
--- a/InvenTree/part/templates/part/tabs.html
+++ b/InvenTree/part/templates/part/tabs.html
@@ -15,12 +15,12 @@
{% endif %}
{% if not part.virtual %}
- {% trans "Stock" %} {% decimal part.total_stock %}
+ {% trans "Stock" %} {% decimal total_stock %}
{% endif %}
{% if part.component or part.salable or part.used_in_count > 0 %}
- {% trans "Allocated" %} {% decimal part.allocation_count %}
+ {% trans "Allocated" %} {% decimal allocated %}
{% endif %}
{% if part.assembly %}
diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py
index 8f1c86fdfc..745650b55d 100644
--- a/InvenTree/part/views.py
+++ b/InvenTree/part/views.py
@@ -792,6 +792,22 @@ class PartDetail(InvenTreeRoleMixin, DetailView):
context['starred'] = part.isStarredBy(self.request.user)
context['disabled'] = not part.active
+ # Pre-calculate complex queries so they only need to be performed once
+ context['total_stock'] = part.total_stock
+
+ context['quantity_being_built'] = part.quantity_being_built
+
+ context['required_build_order_quantity'] = part.required_build_order_quantity()
+ context['allocated_build_order_quantity'] = part.build_order_allocation_count()
+
+ context['required_sales_order_quantity'] = part.required_sales_order_quantity()
+ context['allocated_sales_order_quantity'] = part.sales_order_allocation_count()
+
+ context['available'] = part.available_stock
+ context['on_order'] = part.on_order
+ context['required'] = context['required_build_order_quantity'] + context['required_sales_order_quantity']
+ context['allocated'] = context['allocated_build_order_quantity'] + context['allocated_sales_order_quantity']
+
return context
diff --git a/InvenTree/report/admin.py b/InvenTree/report/admin.py
index 610b32dd4c..2c008877cc 100644
--- a/InvenTree/report/admin.py
+++ b/InvenTree/report/admin.py
@@ -3,7 +3,10 @@ from __future__ import unicode_literals
from django.contrib import admin
-from .models import ReportSnippet, TestReport, ReportAsset
+from .models import ReportSnippet, ReportAsset
+from .models import TestReport
+from .models import BuildReport
+from .models import BillOfMaterialsReport
class ReportTemplateAdmin(admin.ModelAdmin):
@@ -22,5 +25,8 @@ class ReportAssetAdmin(admin.ModelAdmin):
admin.site.register(ReportSnippet, ReportSnippetAdmin)
-admin.site.register(TestReport, ReportTemplateAdmin)
admin.site.register(ReportAsset, ReportAssetAdmin)
+
+admin.site.register(TestReport, ReportTemplateAdmin)
+admin.site.register(BuildReport, ReportTemplateAdmin)
+admin.site.register(BillOfMaterialsReport, ReportTemplateAdmin)
diff --git a/InvenTree/report/api.py b/InvenTree/report/api.py
index 560cf706de..dd937f0aba 100644
--- a/InvenTree/report/api.py
+++ b/InvenTree/report/api.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.conf.urls import url, include
+from django.core.exceptions import ValidationError, FieldError
from django.http import HttpResponse
from django_filters.rest_framework import DjangoFilterBackend
@@ -15,8 +16,16 @@ import InvenTree.helpers
from stock.models import StockItem
+import build.models
+import part.models
+
from .models import TestReport
+from .models import BuildReport
+from .models import BillOfMaterialsReport
+
from .serializers import TestReportSerializer
+from .serializers import BuildReportSerializer
+from .serializers import BOMReportSerializer
class ReportListView(generics.ListAPIView):
@@ -53,13 +62,7 @@ class StockItemReportMixin:
params = self.request.query_params
- if 'items[]' in params:
- items = params.getlist('items[]', [])
- elif 'item' in params:
- items = [params.get('item', None)]
-
- if type(items) not in [list, tuple]:
- item = [items]
+ items = params.getlist('item', [])
valid_ids = []
@@ -75,6 +78,131 @@ class StockItemReportMixin:
return valid_items
+class BuildReportMixin:
+ """
+ Mixin for extracting Build items from query params
+ """
+
+ def get_builds(self):
+ """
+ Return a list of requested Build objects
+ """
+
+ builds = []
+
+ params = self.request.query_params
+
+ builds = params.getlist('build', [])
+
+ valid_ids = []
+
+ for b in builds:
+ try:
+ valid_ids.append(int(b))
+ except (ValueError):
+ continue
+
+ return build.models.Build.objects.filter(pk__in=valid_ids)
+
+
+class PartReportMixin:
+ """
+ Mixin for extracting part items from query params
+ """
+
+ def get_parts(self):
+ """
+ Return a list of requested part objects
+ """
+
+ parts = []
+
+ params = self.request.query_params
+
+ parts = params.getlist('part', [])
+
+ valid_ids = []
+
+ for p in parts:
+ try:
+ valid_ids.append(int(p))
+ except (ValueError):
+ continue
+
+ # Extract a valid set of Part objects
+ valid_parts = part.models.Part.objects.filter(pk__in=valid_ids)
+
+ return valid_parts
+
+
+class ReportPrintMixin:
+ """
+ Mixin for printing reports
+ """
+
+ def print(self, request, items_to_print):
+ """
+ Print this report template against a number of pre-validated items.
+ """
+
+ if len(items_to_print) == 0:
+ # No valid items provided, return an error message
+ data = {
+ 'error': _('No valid objects provided to template'),
+ }
+
+ return Response(data, status=400)
+
+ outputs = []
+
+ # In debug mode, generate single HTML output, rather than PDF
+ debug_mode = common.models.InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
+
+ # Merge one or more PDF files into a single download
+ for item in items_to_print:
+ report = self.get_object()
+ report.object_to_print = item
+
+ if debug_mode:
+ outputs.append(report.render_to_string(request))
+ else:
+ outputs.append(report.render(request))
+
+ if debug_mode:
+ """
+ Contatenate all rendered templates into a single HTML string,
+ and return the string as a HTML response.
+ """
+
+ html = "\n".join(outputs)
+
+ return HttpResponse(html)
+ else:
+ """
+ Concatenate all rendered pages into a single PDF object,
+ and return the resulting document!
+ """
+
+ pages = []
+
+ if len(outputs) > 1:
+ # If more than one output is generated, merge them into a single file
+ for output in outputs:
+ doc = output.get_document()
+ for page in doc.pages:
+ pages.append(page)
+
+ pdf = outputs[0].get_document().copy(pages).write_pdf()
+ else:
+ pdf = outputs[0].get_document().write_pdf()
+
+ return InvenTree.helpers.DownloadFile(
+ pdf,
+ 'inventree_report.pdf',
+ content_type='application/pdf'
+ )
+
+
class StockItemTestReportList(ReportListView, StockItemReportMixin):
"""
API endpoint for viewing list of TestReport objects.
@@ -82,8 +210,7 @@ class StockItemTestReportList(ReportListView, StockItemReportMixin):
Filterable by:
- enabled: Filter by enabled / disabled status
- - item: Filter by single stock item
- - items: Filter by list of stock items
+ - item: Filter by stock item(s)
"""
@@ -114,12 +241,19 @@ class StockItemTestReportList(ReportListView, StockItemReportMixin):
matches = True
# Filter string defined for the report object
- filters = InvenTree.helpers.validateFilterString(report.filters)
+ try:
+ filters = InvenTree.helpers.validateFilterString(report.filters)
+ except:
+ continue
for item in items:
item_query = StockItem.objects.filter(pk=item.pk)
- if not item_query.filter(**filters).exists():
+ try:
+ if not item_query.filter(**filters).exists():
+ matches = False
+ break
+ except FieldError:
matches = False
break
@@ -142,7 +276,7 @@ class StockItemTestReportDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = TestReportSerializer
-class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin):
+class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin, ReportPrintMixin):
"""
API endpoint for printing a TestReport object
"""
@@ -157,67 +291,212 @@ class StockItemTestReportPrint(generics.RetrieveAPIView, StockItemReportMixin):
items = self.get_items()
- if len(items) == 0:
- # No valid items provided, return an error message
- data = {
- 'error': _('Must provide valid StockItem(s)')
- }
+ return self.print(request, items)
+
- return Response(data, status=400)
+class BOMReportList(ReportListView, PartReportMixin):
+ """
+ API endpoint for viewing a list of BillOfMaterialReport objects.
- outputs = []
+ Filterably by:
- # In debug mode, generate single HTML output, rather than PDF
- debug_mode = common.models.InvenTreeSetting.get_setting('REPORT_DEBUG_MODE')
+ - enabled: Filter by enabled / disabled status
+ - part: Filter by part(s)
+ """
- # Merge one or more PDF files into a single download
- for item in items:
- report = self.get_object()
- report.stock_item = item
+ queryset = BillOfMaterialsReport.objects.all()
+ serializer_class = BOMReportSerializer
- if debug_mode:
- outputs.append(report.render_to_string(request))
- else:
- outputs.append(report.render(request))
+ def filter_queryset(self, queryset):
- if debug_mode:
+ queryset = super().filter_queryset(queryset)
+
+ # List of Part objects to match against
+ parts = self.get_parts()
+
+ if len(parts) > 0:
"""
- Contatenate all rendered templates into a single HTML string,
- and return the string as a HTML response.
+ We wish to filter by part(s).
+
+ We need to compare the 'filters' string of each report,
+ and see if it matches against each of the specified parts.
"""
- html = "\n".join(outputs)
+ valid_report_ids = set()
- return HttpResponse(html)
+ for report in queryset.all():
- else:
+ matches = True
+
+ try:
+ filters = InvenTree.helpers.validateFilterString(report.filters)
+ except ValidationError:
+ # Filters are ill-defined
+ continue
+
+ for p in parts:
+ part_query = part.models.Part.objects.filter(pk=p.pk)
+
+ try:
+ if not part_query.filter(**filters).exists():
+ matches = False
+ break
+ except FieldError:
+ matches = False
+ break
+
+ if matches:
+ valid_report_ids.add(report.pk)
+ else:
+ continue
+
+ # Reduce queryset to only valid matches
+ queryset = queryset.filter(pk__in=[pk for pk in valid_report_ids])
+
+ return queryset
+
+
+class BOMReportDetail(generics.RetrieveUpdateDestroyAPIView):
+ """
+ API endpoint for a single BillOfMaterialReport object
+ """
+
+ queryset = BillOfMaterialsReport.objects.all()
+ serializer_class = BOMReportSerializer
+
+
+class BOMReportPrint(generics.RetrieveAPIView, PartReportMixin, ReportPrintMixin):
+ """
+ API endpoint for printing a BillOfMaterialReport object
+ """
+
+ queryset = BillOfMaterialsReport.objects.all()
+ serializer_class = BOMReportSerializer
+
+ def get(self, request, *args, **kwargs):
+ """
+ Check if valid part item(s) have been provided
+ """
+
+ parts = self.get_parts()
+
+ return self.print(request, parts)
+
+
+class BuildReportList(ReportListView, BuildReportMixin):
+ """
+ API endpoint for viewing a list of BuildReport objects.
+
+ Can be filtered by:
+
+ - enabled: Filter by enabled / disabled status
+ - build: Filter by Build object
+ """
+
+ queryset = BuildReport.objects.all()
+ serializer_class = BuildReportSerializer
+
+ def filter_queryset(self, queryset):
+
+ queryset = super().filter_queryset(queryset)
+
+ # List of Build objects to match against
+ builds = self.get_builds()
+
+ if len(builds) > 0:
"""
- Concatenate all rendered pages into a single PDF object,
- and return the resulting document!
+ We wish to filter by Build(s)
+
+ We need to compare the 'filters' string of each report,
+ and see if it matches against each of the specified parts
+
+ # TODO: This code needs some refactoring!
"""
- pages = []
+ valid_build_ids = set()
- if len(outputs) > 1:
- # If more than one output is generated, merge them into a single file
- for output in outputs:
- doc = output.get_document()
- for page in doc.pages:
- pages.append(page)
+ for report in queryset.all():
- pdf = outputs[0].get_document().copy(pages).write_pdf()
- else:
- pdf = outputs[0].get_document().write_pdf()
+ matches = True
- return InvenTree.helpers.DownloadFile(
- pdf,
- 'test_report.pdf',
- content_type='application/pdf'
- )
+ try:
+ filters = InvenTree.helpers.validateFilterString(report.filters)
+ except ValidationError:
+ continue
+
+ for b in builds:
+ build_query = build.models.Build.objects.filter(pk=b.pk)
+
+ try:
+ if not build_query.filter(**filters).exists():
+ matches = False
+ break
+ except FieldError:
+ matches = False
+ break
+
+ if matches:
+ valid_build_ids.add(report.pk)
+ else:
+ continue
+
+ # Reduce queryset to only valid matches
+ queryset = queryset.filter(pk__in=[pk for pk in valid_build_ids])
+
+ return queryset
+
+
+class BuildReportDetail(generics.RetrieveUpdateDestroyAPIView):
+ """
+ API endpoint for a single BuildReport object
+ """
+
+ queryset = BuildReport.objects.all()
+ serializer_class = BuildReportSerializer
+
+
+class BuildReportPrint(generics.RetrieveAPIView, BuildReportMixin, ReportPrintMixin):
+ """
+ API endpoint for printing a BuildReport
+ """
+
+ queryset = BuildReport.objects.all()
+ serializer_class = BuildReportSerializer
+
+ def get(self, request, *ars, **kwargs):
+
+ builds = self.get_builds()
+
+ return self.print(request, builds)
report_api_urls = [
+ # Build reports
+ url(r'build/', include([
+ # Detail views
+ url(r'^(?P\d+)/', include([
+ url(r'print/?', BuildReportPrint.as_view(), name='api-build-report-print'),
+ url(r'^.*$', BuildReportDetail.as_view(), name='api-build-report-detail'),
+ ])),
+
+ # List view
+ url(r'^.*$', BuildReportList.as_view(), name='api-build-report-list'),
+ ])),
+
+ # Bill of Material reports
+ url(r'bom/', include([
+
+ # Detail views
+ url(r'^(?P\d+)/', include([
+ url(r'print/?', BOMReportPrint.as_view(), name='api-bom-report-print'),
+ url(r'^.*$', BOMReportDetail.as_view(), name='api-bom-report-detail'),
+ ])),
+
+ # List view
+ url(r'^.*$', BOMReportList.as_view(), name='api-bom-report-list'),
+ ])),
+
# Stock item test reports
url(r'test/', include([
# Detail views
diff --git a/InvenTree/report/apps.py b/InvenTree/report/apps.py
index bb1c5f0cb7..941133e481 100644
--- a/InvenTree/report/apps.py
+++ b/InvenTree/report/apps.py
@@ -18,6 +18,66 @@ class ReportConfig(AppConfig):
"""
self.create_default_test_reports()
+ self.create_default_build_reports()
+
+ def create_default_reports(self, model, reports):
+ """
+ Copy defualt report files across to the media directory.
+ """
+
+ # Source directory for report templates
+ src_dir = os.path.join(
+ os.path.dirname(os.path.realpath(__file__)),
+ 'templates',
+ 'report',
+ )
+
+ # Destination directory
+ dst_dir = os.path.join(
+ settings.MEDIA_ROOT,
+ 'report',
+ 'inventree',
+ model.getSubdir(),
+ )
+
+ if not os.path.exists(dst_dir):
+ logger.info(f"Creating missing directory: '{dst_dir}'")
+ os.makedirs(dst_dir, exist_ok=True)
+
+ # Copy each report template across (if required)
+ for report in reports:
+
+ # Destination filename
+ filename = os.path.join(
+ 'report',
+ 'inventree',
+ model.getSubdir(),
+ report['file'],
+ )
+
+ src_file = os.path.join(src_dir, report['file'])
+ dst_file = os.path.join(settings.MEDIA_ROOT, filename)
+
+ if not os.path.exists(dst_file):
+ logger.info(f"Copying test report template '{dst_file}'")
+ shutil.copyfile(src_file, dst_file)
+
+ try:
+ # Check if a report matching the template already exists
+ if model.objects.filter(template=filename).exists():
+ continue
+
+ logger.info(f"Creating new TestReport for '{report['name']}'")
+
+ model.objects.create(
+ name=report['name'],
+ description=report['description'],
+ template=filename,
+ enabled=True
+ )
+
+ except:
+ pass
def create_default_test_reports(self):
"""
@@ -31,23 +91,6 @@ class ReportConfig(AppConfig):
# Database is not ready yet
return
- src_dir = os.path.join(
- os.path.dirname(os.path.realpath(__file__)),
- 'templates',
- 'report',
- )
-
- dst_dir = os.path.join(
- settings.MEDIA_ROOT,
- 'report',
- 'inventree', # Stored in secret directory!
- 'test',
- )
-
- if not os.path.exists(dst_dir):
- logger.info(f"Creating missing directory: '{dst_dir}'")
- os.makedirs(dst_dir, exist_ok=True)
-
# List of test reports to copy across
reports = [
{
@@ -57,36 +100,27 @@ class ReportConfig(AppConfig):
},
]
- for report in reports:
+ self.create_default_reports(TestReport, reports)
- # Create destination file name
- filename = os.path.join(
- 'report',
- 'inventree',
- 'test',
- report['file']
- )
+ def create_default_build_reports(self):
+ """
+ Create database entries for the default BuildReport templates
+ (if they do not already exist)
+ """
- src_file = os.path.join(src_dir, report['file'])
- dst_file = os.path.join(settings.MEDIA_ROOT, filename)
+ try:
+ from .models import BuildReport
+ except:
+ # Database is not ready yet
+ return
- if not os.path.exists(dst_file):
- logger.info(f"Copying test report template '{dst_file}'")
- shutil.copyfile(src_file, dst_file)
+ # List of Build reports to copy across
+ reports = [
+ {
+ 'file': 'inventree_build_order.html',
+ 'name': 'InvenTree Build Order',
+ 'description': 'Build Order job sheet',
+ }
+ ]
- try:
- # Check if a report matching the template already exists
- if TestReport.objects.filter(template=filename).exists():
- continue
-
- logger.info(f"Creating new TestReport for '{report['name']}'")
-
- TestReport.objects.create(
- name=report['name'],
- description=report['description'],
- template=filename,
- filters='',
- enabled=True
- )
- except:
- pass
+ self.create_default_reports(BuildReport, reports)
diff --git a/InvenTree/report/migrations/0011_auto_20210212_2024.py b/InvenTree/report/migrations/0011_auto_20210212_2024.py
new file mode 100644
index 0000000000..b1a93656cf
--- /dev/null
+++ b/InvenTree/report/migrations/0011_auto_20210212_2024.py
@@ -0,0 +1,35 @@
+# Generated by Django 3.0.7 on 2021-02-12 09:24
+
+import django.core.validators
+from django.db import migrations, models
+import report.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('report', '0010_auto_20210205_1201'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BillOfMaterialsReport',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(help_text='Template name', max_length=100, verbose_name='Name')),
+ ('template', models.FileField(help_text='Report template file', upload_to=report.models.rename_template, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html', 'htm'])], verbose_name='Template')),
+ ('description', models.CharField(help_text='Report template description', max_length=250, verbose_name='Description')),
+ ('revision', models.PositiveIntegerField(default=1, editable=False, help_text='Report revision number (auto-increments)', verbose_name='Revision')),
+ ('enabled', models.BooleanField(default=True, help_text='Report template is enabled', verbose_name='Enabled')),
+ ('filters', models.CharField(blank=True, help_text='Part query filters (comma-separated list of key=value pairs', max_length=250, validators=[report.models.validate_part_report_filters], verbose_name='Part Filters')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ migrations.AlterField(
+ model_name='testreport',
+ name='filters',
+ field=models.CharField(blank=True, help_text='StockItem query filters (comma-separated list of key=value pairs)', max_length=250, validators=[report.models.validate_stock_item_report_filters], verbose_name='Filters'),
+ ),
+ ]
diff --git a/InvenTree/report/migrations/0012_buildreport.py b/InvenTree/report/migrations/0012_buildreport.py
new file mode 100644
index 0000000000..b2d3603480
--- /dev/null
+++ b/InvenTree/report/migrations/0012_buildreport.py
@@ -0,0 +1,30 @@
+# Generated by Django 3.0.7 on 2021-02-15 21:08
+
+import django.core.validators
+from django.db import migrations, models
+import report.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('report', '0011_auto_20210212_2024'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BuildReport',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(help_text='Template name', max_length=100, verbose_name='Name')),
+ ('template', models.FileField(help_text='Report template file', upload_to=report.models.rename_template, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['html', 'htm'])], verbose_name='Template')),
+ ('description', models.CharField(help_text='Report template description', max_length=250, verbose_name='Description')),
+ ('revision', models.PositiveIntegerField(default=1, editable=False, help_text='Report revision number (auto-increments)', verbose_name='Revision')),
+ ('enabled', models.BooleanField(default=True, help_text='Report template is enabled', verbose_name='Enabled')),
+ ('filters', models.CharField(blank=True, help_text='Build query filters (comma-separated list of key=value pairs', max_length=250, validators=[report.models.validate_build_report_filters], verbose_name='Build Filters')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ ]
diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py
index ddb7e9ea94..4ab6a25bf4 100644
--- a/InvenTree/report/models.py
+++ b/InvenTree/report/models.py
@@ -13,14 +13,17 @@ import datetime
from django.db import models
from django.conf import settings
+from django.core.exceptions import ValidationError, FieldError
from django.template.loader import render_to_string
from django.core.files.storage import FileSystemStorage
from django.core.validators import FileExtensionValidator
-import stock.models
+import build.models
import common.models
+import part.models
+import stock.models
from InvenTree.helpers import validateFilterString
@@ -59,7 +62,6 @@ class ReportFileUpload(FileSystemStorage):
def get_available_name(self, name, max_length=None):
- print("Name:", name)
return super().get_available_name(name, max_length)
@@ -69,10 +71,29 @@ def rename_template(instance, filename):
def validate_stock_item_report_filters(filters):
+ """
+ Validate filter string against StockItem model
+ """
return validateFilterString(filters, model=stock.models.StockItem)
+def validate_part_report_filters(filters):
+ """
+ Validate filter string against Part model
+ """
+
+ return validateFilterString(filters, model=part.models.Part)
+
+
+def validate_build_report_filters(filters):
+ """
+ Validate filter string against Build model
+ """
+
+ return validateFilterString(filters, model=build.models.Build)
+
+
class WeasyprintReportMixin(WeasyTemplateResponseMixin):
"""
Class for rendering a HTML template to a PDF.
@@ -106,7 +127,8 @@ class ReportBase(models.Model):
def __str__(self):
return "{n} - {d}".format(n=self.name, d=self.description)
- def getSubdir(self):
+ @classmethod
+ def getSubdir(cls):
return ''
def rename_file(self, filename):
@@ -170,6 +192,9 @@ class ReportTemplateBase(ReportBase):
"""
+ # Pass a single top-level object to the report template
+ object_to_print = None
+
def get_context_data(self, request):
"""
Supply context data to the template for rendering
@@ -184,6 +209,7 @@ class ReportTemplateBase(ReportBase):
context = self.get_context_data(request)
+ context['base_url'] = common.models.InvenTreeSetting.get_setting('INVENTREE_BASE_URL')
context['date'] = datetime.datetime.now().date()
context['datetime'] = datetime.datetime.now()
context['default_page_size'] = common.models.InvenTreeSetting.get_setting('REPORT_DEFAULT_PAGE_SIZE')
@@ -241,17 +267,15 @@ class TestReport(ReportTemplateBase):
Render a TestReport against a StockItem object.
"""
- def getSubdir(self):
+ @classmethod
+ def getSubdir(cls):
return 'test'
- # Requires a stock_item object to be given to it before rendering
- stock_item = None
-
filters = models.CharField(
blank=True,
max_length=250,
verbose_name=_('Filters'),
- help_text=_("Part query filters (comma-separated list of key=value pairs)"),
+ help_text=_("StockItem query filters (comma-separated list of key=value pairs)"),
validators=[
validate_stock_item_report_filters
]
@@ -262,9 +286,11 @@ class TestReport(ReportTemplateBase):
Test if this report template matches a given StockItem objects
"""
- filters = validateFilterString(self.filters)
-
- items = stock.models.StockItem.objects.filter(**filters)
+ try:
+ filters = validateFilterString(self.filters)
+ items = stock.models.StockItem.objects.filter(**filters)
+ except (ValidationError, FieldError):
+ return False
# Ensure the provided StockItem object matches the filters
items = items.filter(pk=item.pk)
@@ -272,11 +298,82 @@ class TestReport(ReportTemplateBase):
return items.exists()
def get_context_data(self, request):
+
+ stock_item = self.object_to_print
+
return {
- 'stock_item': self.stock_item,
- 'part': self.stock_item.part,
- 'results': self.stock_item.testResultMap(),
- 'result_list': self.stock_item.testResultList()
+ 'stock_item': stock_item,
+ 'part': stock_item.part,
+ 'results': stock_item.testResultMap(),
+ 'result_list': stock_item.testResultList()
+ }
+
+
+class BuildReport(ReportTemplateBase):
+ """
+ Build order / work order report
+ """
+
+ @classmethod
+ def getSubdir(cls):
+ return 'build'
+
+ filters = models.CharField(
+ blank=True,
+ max_length=250,
+ verbose_name=_('Build Filters'),
+ help_text=_('Build query filters (comma-separated list of key=value pairs'),
+ validators=[
+ validate_build_report_filters,
+ ]
+ )
+
+ def get_context_data(self, request):
+ """
+ Custom context data for the build report
+ """
+
+ my_build = self.object_to_print
+
+ if not type(my_build) == build.models.Build:
+ raise TypeError('Provided model is not a Build object')
+
+ return {
+ 'build': my_build,
+ 'part': my_build.part,
+ 'bom_items': my_build.part.get_bom_items(),
+ 'reference': my_build.reference,
+ 'quantity': my_build.quantity,
+ }
+
+
+class BillOfMaterialsReport(ReportTemplateBase):
+ """
+ Render a Bill of Materials against a Part object
+ """
+
+ @classmethod
+ def getSubdir(cls):
+ return 'bom'
+
+ filters = models.CharField(
+ blank=True,
+ max_length=250,
+ verbose_name=_('Part Filters'),
+ help_text=_('Part query filters (comma-separated list of key=value pairs'),
+ validators=[
+ validate_part_report_filters
+ ]
+ )
+
+ def get_context_data(self, request):
+
+ part = self.object_to_print
+
+ return {
+ 'part': part,
+ 'category': part.category,
+ 'bom_items': part.get_bom_items(),
}
diff --git a/InvenTree/report/serializers.py b/InvenTree/report/serializers.py
index 0cd4d4f40a..f0a449ae49 100644
--- a/InvenTree/report/serializers.py
+++ b/InvenTree/report/serializers.py
@@ -5,6 +5,8 @@ from InvenTree.serializers import InvenTreeModelSerializer
from InvenTree.serializers import InvenTreeAttachmentSerializerField
from .models import TestReport
+from .models import BuildReport
+from .models import BillOfMaterialsReport
class TestReportSerializer(InvenTreeModelSerializer):
@@ -21,3 +23,35 @@ class TestReportSerializer(InvenTreeModelSerializer):
'filters',
'enabled',
]
+
+
+class BuildReportSerializer(InvenTreeModelSerializer):
+
+ template = InvenTreeAttachmentSerializerField(required=True)
+
+ class Meta:
+ model = BuildReport
+ fields = [
+ 'pk',
+ 'name',
+ 'description',
+ 'template',
+ 'filters',
+ 'enabled',
+ ]
+
+
+class BOMReportSerializer(InvenTreeModelSerializer):
+
+ template = InvenTreeAttachmentSerializerField(required=True)
+
+ class Meta:
+ model = BillOfMaterialsReport
+ fields = [
+ 'pk',
+ 'name',
+ 'description',
+ 'template',
+ 'filters',
+ 'enabled',
+ ]
diff --git a/InvenTree/report/templates/report/inventree_build_order.html b/InvenTree/report/templates/report/inventree_build_order.html
new file mode 100644
index 0000000000..72e52a889a
--- /dev/null
+++ b/InvenTree/report/templates/report/inventree_build_order.html
@@ -0,0 +1,3 @@
+{% extends "report/inventree_build_order_base.html" %}
+
+
diff --git a/InvenTree/report/templates/report/inventree_build_order_base.html b/InvenTree/report/templates/report/inventree_build_order_base.html
new file mode 100644
index 0000000000..0a4f8b3bb6
--- /dev/null
+++ b/InvenTree/report/templates/report/inventree_build_order_base.html
@@ -0,0 +1,182 @@
+{% extends "report/inventree_report_base.html" %}
+
+{% load i18n %}
+{% load report %}
+{% load inventree_extras %}
+{% load markdownify %}
+{% load qr_code %}
+
+{% block page_margin %}
+margin: 2cm;
+margin-top: 4cm;
+{% endblock %}
+
+{% block style %}
+
+.header-right {
+ text-align: right;
+ float: right;
+}
+
+.logo {
+ height: 20mm;
+ vertical-align: middle;
+}
+
+.part-image {
+ border: 1px solid;
+ border-radius: 2px;
+ vertical-align: middle;
+ height: 40mm;
+ width: 100%;
+ display: inline-block;
+ z-index: 100;
+}
+
+.details-image {
+ float: right;
+ width: 30%;
+}
+
+.details {
+ width: 100%;
+ border: 1px solid;
+ border-radius: 3px;
+ padding: 5px;
+ min-height: 42mm;
+}
+
+.details table {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ width: 65%;
+ table-layout: fixed;
+ font-size: 75%;
+}
+
+.details table td:not(:last-child){
+ white-space: nowrap;
+}
+
+.details table td:last-child{
+ width: 50%;
+ padding-left: 1cm;
+ padding-right: 1cm;
+}
+
+.details-table td {
+ padding-left: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ border-bottom: 1px solid #555;
+}
+
+{% endblock %}
+
+{% block bottom_left %}
+content: "v{{report_revision}} - {{ date.isoformat }}";
+{% endblock %}
+
+{% block bottom_center %}
+content: "www.currawong.aero";
+{% endblock %}
+
+{% block header_content %}
+
+
+
+
+
+{% endblock %}
+
+{% block page_content %}
+
+
+
+
+
+
+
+
+
+
+ {% trans "Build Order" %} |
+ {% internal_link build.get_absolute_url build %} |
+
+
+ {% trans "Part" %} |
+ {% internal_link part.get_absolute_url part.full_name %} |
+
+
+ {% trans "Quantity" %} |
+ {{ build.quantity }} |
+
+
+ {% trans "Description" %} |
+ {{ build.title }} |
+
+
+ {% trans "Issued" %} |
+ {{ build.creation_date }} |
+
+
+ {% trans "Target Date" %} |
+
+ {% if build.target_date %}
+ {{ build.target_date }}
+ {% else %}
+ Not specified
+ {% endif %}
+ |
+
+
+ {% trans "Sales Order" %} |
+
+ {% if build.sales_order %}
+ {% internal_link build.sales_order.get_absolute_url build.sales_order %}
+ {% else %}
+ Not specified
+ {% endif %}
+ |
+
+ {% if build.parent %}
+
+ {% trans "Required For" %} |
+ {% internal_link build.parent.get_absolute_url build.parent %} |
+
+ {% endif %}
+ {% if build.issued_by %}
+
+ {% trans "Issued By" %} |
+ {{ build.issued_by }} |
+
+ {% endif %}
+ {% if build.responsible %}
+
+ {% trans "Responsible" %} |
+ {{ build.responsible }} |
+
+ {% endif %}
+ {% if build.link %}
+
+ {% trans "Link" %} |
+ {{ build.link }} |
+
+ {% endif %}
+
+
+
+
+{% trans "Notes" %}
+
+{% if build.notes %}
+{{ build.notes|markdownify }}
+{% endif %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/report/templates/report/inventree_report_base.html b/InvenTree/report/templates/report/inventree_report_base.html
index 7c2cff8b4a..a8919ac72d 100644
--- a/InvenTree/report/templates/report/inventree_report_base.html
+++ b/InvenTree/report/templates/report/inventree_report_base.html
@@ -4,8 +4,12 @@
InvenTree
-
+
+
+
+
-
+
+
+
diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py
index 351b6f7370..dfe0acc968 100644
--- a/InvenTree/users/models.py
+++ b/InvenTree/users/models.py
@@ -120,6 +120,8 @@ class RuleSet(models.Model):
'report_reportasset',
'report_reportsnippet',
'report_testreport',
+ 'report_buildreport',
+ 'report_billofmaterialsreport',
'part_partstar',
'users_owner',
diff --git a/tasks.py b/tasks.py
index 77604eaf3a..579887c809 100644
--- a/tasks.py
+++ b/tasks.py
@@ -349,12 +349,22 @@ def backup(c):
Create a backup of database models and uploaded media files.
Backup files will be written to the 'backup_dir' file specified in 'config.yaml'
-
"""
manage(c, 'dbbackup')
manage(c, 'mediabackup')
+@task
+def restore(c):
+ """
+ Restores database models and media files.
+
+ Backup files are read from the 'backup_dir' file specified in 'config.yaml'
+ """
+
+ manage(c, 'dbrestore')
+ manage(c, 'mediarestore')
+
@task(help={'address': 'Server address:port (default=127.0.0.1:8000)'})
def server(c, address="127.0.0.1:8000"):
"""