Merge pull request #1092 from SchrodingersGat/copy-bom

Copy bom
This commit is contained in:
Oliver 2020-10-30 11:40:06 +11:00 committed by GitHub
commit 1311e5fe58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 722 additions and 423 deletions

View File

@ -213,6 +213,39 @@ class AjaxMixin(InvenTreeRoleMixin):
"""
return {}
def pre_save(self, obj, form, **kwargs):
"""
Hook for doing something *before* an object is saved.
obj: The object to be saved
form: The cleaned form
"""
# Do nothing by default
pass
def post_save(self, obj, form, **kwargs):
"""
Hook for doing something *after* an object is saved.
"""
# Do nothing by default
pass
def validate(self, obj, form, **kwargs):
"""
Hook for performing custom form validation steps.
If a form error is detected, add it to the form,
with 'form.add_error()'
Ref: https://docs.djangoproject.com/en/dev/topics/forms/
"""
# Do nothing by default
pass
def renderJsonResponse(self, request, form=None, data={}, context=None):
""" Render a JSON response based on specific class context.
@ -320,18 +353,6 @@ class AjaxCreateView(AjaxMixin, CreateView):
- Handles form validation via AJAX POST requests
"""
def pre_save(self, **kwargs):
"""
Hook for doing something before the form is validated
"""
pass
def post_save(self, **kwargs):
"""
Hook for doing something with the created object after it is saved
"""
pass
def get(self, request, *args, **kwargs):
""" Creates form with initial data, and renders JSON response """
@ -351,16 +372,29 @@ class AjaxCreateView(AjaxMixin, CreateView):
self.request = request
self.form = self.get_form()
# Perform initial form validation
self.form.is_valid()
# Perform custom validation (no object can be provided yet)
self.validate(None, self.form)
valid = self.form.is_valid()
# Extra JSON data sent alongside form
data = {
'form_valid': self.form.is_valid(),
'form_valid': valid
}
if self.form.is_valid():
if valid:
self.pre_save()
# Perform (optional) pre-save step
self.pre_save(None, self.form)
# Save the object to the database
self.object = self.form.save()
self.post_save()
# Perform (optional) post-save step
self.post_save(self.object, self.form)
# Return the PK of the newly-created object
data['pk'] = self.object.pk
@ -400,22 +434,40 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
- Otherwise, return sucess status
"""
self.request = request
# Make sure we have an object to point to
self.object = self.get_object()
form = self.get_form()
# Perform initial form validation
form.is_valid()
# Perform custom validation
self.validate(self.object, form)
valid = form.is_valid()
data = {
'form_valid': form.is_valid()
'form_valid': valid
}
if form.is_valid():
if valid:
# Perform (optional) pre-save step
self.pre_save(self.object, form)
# Save the updated objec to the database
obj = form.save()
# Include context data about the updated object
data['pk'] = obj.id
# Perform (optional) post-save step
self.post_save(obj, form)
self.post_save(obj)
# Include context data about the updated object
data['pk'] = obj.pk
self.post_save(obj, form)
try:
data['url'] = obj.get_absolute_url()
@ -424,13 +476,6 @@ class AjaxUpdateView(AjaxMixin, UpdateView):
return self.renderJsonResponse(request, form, data)
def post_save(self, obj, *args, **kwargs):
"""
Hook called after the form data is saved.
(Optional)
"""
pass
class AjaxDeleteView(AjaxMixin, UpdateView):

View File

@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-29 02:25+0000\n"
"POT-Creation-Date: 2020-10-29 23:05+0000\n"
"PO-Revision-Date: 2020-05-03 11:32+0200\n"
"Last-Translator: Christian Schlüter <chschlue@gmail.com>\n"
"Language-Team: C <kde-i18n-doc@kde.org>\n"
@ -214,7 +214,7 @@ msgstr "Überschuss darf 100% nicht überschreiten"
msgid "Overage must be an integer value or a percentage"
msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein"
#: InvenTree/views.py:707
#: InvenTree/views.py:752
msgid "Database Statistics"
msgstr "Datenbankstatistiken"
@ -547,7 +547,7 @@ msgstr "Zuweisung löschen"
msgid "No BOM items found"
msgstr "Keine BOM-Einträge gefunden"
#: build/templates/build/allocate.html:347 part/models.py:1401
#: build/templates/build/allocate.html:347 part/models.py:1425
#: templates/js/part.js:569 templates/js/table_filters.js:167
msgid "Required"
msgstr "benötigt"
@ -1279,7 +1279,7 @@ msgstr "Zuliefererbestand"
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
#: part/templates/part/bom.html:62 part/templates/part/category.html:112
#: part/templates/part/bom.html:67 part/templates/part/category.html:112
#: part/templates/part/category.html:126 part/templates/part/stock.html:51
#: templates/stock_table.html:7
msgid "Export"
@ -1398,7 +1398,7 @@ msgid "Pricing Information"
msgstr "Preisinformationen ansehen"
#: company/templates/company/supplier_part_pricing.html:17 company/views.py:410
#: part/templates/part/sale_prices.html:13 part/views.py:2229
#: part/templates/part/sale_prices.html:13 part/views.py:2278
msgid "Add Price Break"
msgstr "Preisstaffel hinzufügen"
@ -1531,17 +1531,17 @@ msgstr "Neues Zuliefererteil anlegen"
msgid "Delete Supplier Part"
msgstr "Zuliefererteil entfernen"
#: company/views.py:416 part/views.py:2235
#: company/views.py:416 part/views.py:2284
#, fuzzy
#| msgid "Add Price Break"
msgid "Added new price break"
msgstr "Preisstaffel hinzufügen"
#: company/views.py:453 part/views.py:2280
#: company/views.py:453 part/views.py:2329
msgid "Edit Price Break"
msgstr "Preisstaffel bearbeiten"
#: company/views.py:469 part/views.py:2296
#: company/views.py:469 part/views.py:2345
msgid "Delete Price Break"
msgstr "Preisstaffel löschen"
@ -1646,7 +1646,7 @@ msgstr ""
msgid "Date order was completed"
msgstr "Bestellung als vollständig markieren"
#: order/models.py:185 order/models.py:259 part/views.py:1346
#: order/models.py:185 order/models.py:259 part/views.py:1395
#: stock/models.py:241 stock/models.py:805
msgid "Quantity must be greater than zero"
msgstr "Anzahl muss größer Null sein"
@ -1934,6 +1934,7 @@ msgstr "Kundenreferenz"
#: order/templates/order/sales_order_cancel.html:8
#: order/templates/order/sales_order_ship.html:9
#: part/templates/part/bom_duplicate.html:12
#: stock/templates/stock/stockitem_convert.html:13
msgid "Warning"
msgstr "Warnung"
@ -2162,75 +2163,97 @@ msgstr "Fehler beim Lesen der Stückliste (ungültige Daten)"
msgid "Error reading BOM file (incorrect row size)"
msgstr "Fehler beim Lesen der Stückliste (ungültige Zeilengröße)"
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "File Format"
msgstr "Dateiformat"
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "Select output file format"
msgstr "Ausgabe-Dateiformat auswählen"
#: part/forms.py:59
#: part/forms.py:64
msgid "Cascading"
msgstr "Kaskadierend"
#: part/forms.py:59
#: part/forms.py:64
msgid "Download cascading / multi-level BOM"
msgstr "Kaskadierende Stückliste herunterladen"
#: part/forms.py:61
#: part/forms.py:66
msgid "Levels"
msgstr ""
#: part/forms.py:61
#: part/forms.py:66
msgid "Select maximum number of BOM levels to export (0 = all levels)"
msgstr ""
#: part/forms.py:63
#: part/forms.py:68
#, fuzzy
#| msgid "New Parameter"
msgid "Include Parameter Data"
msgstr "Neuer Parameter"
#: part/forms.py:63
#: part/forms.py:68
msgid "Include part parameters data in exported BOM"
msgstr ""
#: part/forms.py:65
#: part/forms.py:70
#, fuzzy
#| msgid "Include stock in sublocations"
msgid "Include Stock Data"
msgstr "Bestand in Unterlagerorten einschließen"
#: part/forms.py:65
#: part/forms.py:70
#, fuzzy
#| msgid "Include parts in subcategories"
msgid "Include part stock data in exported BOM"
msgstr "Teile in Unterkategorien einschließen"
#: part/forms.py:67
#: part/forms.py:72
#, fuzzy
#| msgid "New Supplier Part"
msgid "Include Supplier Data"
msgstr "Neues Zulieferer-Teil"
#: part/forms.py:67
#: part/forms.py:72
msgid "Include part supplier data in exported BOM"
msgstr ""
#: part/forms.py:86
#: part/forms.py:93 part/models.py:1504
msgid "Parent Part"
msgstr "Ausgangsteil"
#: part/forms.py:94 part/templates/part/bom_duplicate.html:7
#, fuzzy
#| msgid "Select parent part"
msgid "Select parent part to copy BOM from"
msgstr "Ausgangsteil auswählen"
#: part/forms.py:100
#, fuzzy
#| msgid "Select from existing images"
msgid "Clear existing BOM items"
msgstr "Aus vorhandenen Bildern auswählen"
#: part/forms.py:105
#, fuzzy
#| msgid "Confim BOM item deletion"
msgid "Confirm BOM duplication"
msgstr "Löschung von BOM-Position bestätigen"
#: part/forms.py:123
msgid "Confirm that the BOM is correct"
msgstr "Bestätigen, dass die Stückliste korrekt ist"
#: part/forms.py:98
#: part/forms.py:135
msgid "Select BOM file to upload"
msgstr "Stücklisten-Datei zum Upload auswählen"
#: part/forms.py:122
#: part/forms.py:159
msgid "Select part category"
msgstr "Teilekategorie wählen"
#: part/forms.py:136
#: part/forms.py:173
#, fuzzy
#| msgid "Perform 'deep copy' which will duplicate all BOM data for this part"
msgid "Duplicate all BOM data for this part"
@ -2238,29 +2261,29 @@ msgstr ""
"Tiefe Kopie ausführen. Dies wird alle Daten der Stückliste für dieses Teil "
"duplizieren"
#: part/forms.py:137
#: part/forms.py:174
msgid "Copy BOM"
msgstr ""
#: part/forms.py:142
#: part/forms.py:179
msgid "Duplicate all parameter data for this part"
msgstr ""
#: part/forms.py:143
#: part/forms.py:180
#, fuzzy
#| msgid "Parameters"
msgid "Copy Parameters"
msgstr "Parameter"
#: part/forms.py:148
#: part/forms.py:185
msgid "Confirm part creation"
msgstr "Erstellen des Teils bestätigen"
#: part/forms.py:248
#: part/forms.py:279
msgid "Input quantity for price calculation"
msgstr "Eintragsmenge zur Preisberechnung"
#: part/forms.py:251
#: part/forms.py:282
msgid "Select currency for price calculation"
msgstr "Währung zur Preisberechnung wählen"
@ -2390,13 +2413,13 @@ msgstr "Bemerkungen - unterstüzt Markdown-Formatierung"
msgid "Stored BOM checksum"
msgstr "Prüfsumme der Stückliste gespeichert"
#: part/models.py:1353
#: part/models.py:1377
#, fuzzy
#| msgid "Stock item cannot be created for a template Part"
msgid "Test templates can only be created for trackable parts"
msgstr "Lagerobjekt kann nicht für Vorlagen-Teile angelegt werden"
#: part/models.py:1370
#: part/models.py:1394
#, fuzzy
#| msgid ""
#| "A stock item with this serial number already exists for template part "
@ -2406,120 +2429,116 @@ msgstr ""
"Ein Teil mit dieser Seriennummer existiert bereits für die Teilevorlage "
"{part}"
#: part/models.py:1389 templates/js/part.js:560 templates/js/stock.js:92
#: part/models.py:1413 templates/js/part.js:560 templates/js/stock.js:92
#, fuzzy
#| msgid "Instance Name"
msgid "Test Name"
msgstr "Instanzname"
#: part/models.py:1390
#: part/models.py:1414
#, fuzzy
#| msgid "Serial number for this item"
msgid "Enter a name for the test"
msgstr "Seriennummer für dieses Teil"
#: part/models.py:1395
#: part/models.py:1419
#, fuzzy
#| msgid "Description"
msgid "Test Description"
msgstr "Beschreibung"
#: part/models.py:1396
#: part/models.py:1420
#, fuzzy
#| msgid "Brief description of the build"
msgid "Enter description for this test"
msgstr "Kurze Beschreibung des Baus"
#: part/models.py:1402
#: part/models.py:1426
msgid "Is this test required to pass?"
msgstr ""
#: part/models.py:1407 templates/js/part.js:577
#: part/models.py:1431 templates/js/part.js:577
#, fuzzy
#| msgid "Required Parts"
msgid "Requires Value"
msgstr "benötigte Teile"
#: part/models.py:1408
#: part/models.py:1432
msgid "Does this test require a value when adding a test result?"
msgstr ""
#: part/models.py:1413 templates/js/part.js:584
#: part/models.py:1437 templates/js/part.js:584
#, fuzzy
#| msgid "Delete Attachment"
msgid "Requires Attachment"
msgstr "Anhang löschen"
#: part/models.py:1414
#: part/models.py:1438
msgid "Does this test require a file attachment when adding a test result?"
msgstr ""
#: part/models.py:1447
#: part/models.py:1471
msgid "Parameter template name must be unique"
msgstr "Vorlagen-Name des Parameters muss eindeutig sein"
#: part/models.py:1452
#: part/models.py:1476
msgid "Parameter Name"
msgstr "Name des Parameters"
#: part/models.py:1454
#: part/models.py:1478
msgid "Parameter Units"
msgstr "Parameter Einheit"
#: part/models.py:1480
msgid "Parent Part"
msgstr "Ausgangsteil"
#: part/models.py:1482
#: part/models.py:1506
msgid "Parameter Template"
msgstr "Parameter Vorlage"
#: part/models.py:1484
#: part/models.py:1508
msgid "Parameter Value"
msgstr "Parameter Wert"
#: part/models.py:1521
#: part/models.py:1545
msgid "Select parent part"
msgstr "Ausgangsteil auswählen"
#: part/models.py:1529
#: part/models.py:1553
msgid "Select part to be used in BOM"
msgstr "Teil für die Nutzung in der Stückliste auswählen"
#: part/models.py:1535
#: part/models.py:1559
msgid "BOM quantity for this BOM item"
msgstr "Stücklisten-Anzahl für dieses Stücklisten-Teil"
#: part/models.py:1537
#: part/models.py:1561
#, fuzzy
#| msgid "Confim BOM item deletion"
msgid "This BOM item is optional"
msgstr "Löschung von BOM-Position bestätigen"
#: part/models.py:1540
#: part/models.py:1564
msgid "Estimated build wastage quantity (absolute or percentage)"
msgstr "Geschätzter Ausschuss (absolut oder prozentual)"
#: part/models.py:1543
#: part/models.py:1567
msgid "BOM item reference"
msgstr "Referenz des Objekts auf der Stückliste"
#: part/models.py:1546
#: part/models.py:1570
msgid "BOM item notes"
msgstr "Notizen zum Stücklisten-Objekt"
#: part/models.py:1548
#: part/models.py:1572
msgid "BOM line checksum"
msgstr "Prüfsumme der Stückliste"
#: part/models.py:1612 part/views.py:1352 part/views.py:1404
#: part/models.py:1636 part/views.py:1401 part/views.py:1453
#: stock/models.py:231
#, fuzzy
#| msgid "Overage must be an integer value or a percentage"
msgid "Quantity must be integer value for trackable parts"
msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein"
#: part/models.py:1621
#: part/models.py:1645
#, fuzzy
#| msgid "New BOM Item"
msgid "BOM Item"
@ -2563,64 +2582,80 @@ msgid "Import BOM data"
msgstr "Stückliste importieren"
#: part/templates/part/bom.html:42
msgid "Upload"
msgid "Import from File"
msgstr ""
#: part/templates/part/bom.html:44
#: part/templates/part/bom.html:45
msgid "Copy BOM from parent part"
msgstr ""
#: part/templates/part/bom.html:46
#, fuzzy
#| msgid "Parameters"
msgid "Copy from Parent"
msgstr "Parameter"
#: part/templates/part/bom.html:49
msgid "New BOM Item"
msgstr "Neue Stücklistenposition"
#: part/templates/part/bom.html:45
#: part/templates/part/bom.html:50
#, fuzzy
#| msgid "Add Line Item"
msgid "Add Item"
msgstr "Position hinzufügen"
#: part/templates/part/bom.html:47
#: part/templates/part/bom.html:52
msgid "Finish Editing"
msgstr "Bearbeitung beenden"
#: part/templates/part/bom.html:48
#: part/templates/part/bom.html:53
#, fuzzy
#| msgid "Finish Editing"
msgid "Finished"
msgstr "Bearbeitung beenden"
#: part/templates/part/bom.html:52
#: part/templates/part/bom.html:57
msgid "Edit BOM"
msgstr "Stückliste bearbeiten"
#: part/templates/part/bom.html:53 part/templates/part/params.html:38
#: part/templates/part/bom.html:58 part/templates/part/params.html:38
#: templates/InvenTree/settings/user.html:19
msgid "Edit"
msgstr "Bearbeiten"
#: part/templates/part/bom.html:56
#: part/templates/part/bom.html:61
msgid "Validate Bill of Materials"
msgstr "Stückliste validieren"
#: part/templates/part/bom.html:57
#: part/templates/part/bom.html:62
#, fuzzy
#| msgid "Validate BOM"
msgid "Validate"
msgstr "BOM validieren"
#: part/templates/part/bom.html:61 part/views.py:1643
#: part/templates/part/bom.html:66 part/views.py:1692
msgid "Export Bill of Materials"
msgstr "Stückliste exportieren"
#: part/templates/part/bom.html:122
#: part/templates/part/bom.html:127
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "Delete selected BOM items?"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
#: part/templates/part/bom.html:123
#: part/templates/part/bom.html:128
#, fuzzy
#| msgid "Remove selected BOM items"
msgid "All selected BOM items will be deleted"
msgstr "Ausgewählte Stücklistenpositionen entfernen"
#: part/templates/part/bom_duplicate.html:13
#, fuzzy
#| msgid "Export Bill of Materials"
msgid "This part already has a Bill of Materials"
msgstr "Stückliste exportieren"
#: part/templates/part/bom_upload/select_fields.html:8
#: part/templates/part/bom_upload/select_parts.html:8
#: part/templates/part/bom_upload/upload_file.html:10
@ -2721,7 +2756,7 @@ msgstr "Neuen Bau beginnen"
msgid "All parts"
msgstr "Alle Teile"
#: part/templates/part/category.html:24 part/views.py:2046
#: part/templates/part/category.html:24 part/views.py:2095
msgid "Create new part category"
msgstr "Teilkategorie anlegen"
@ -2895,104 +2930,104 @@ msgstr "Erstellt von"
msgid "Responsible User"
msgstr "Verantwortlicher Benutzer"
#: part/templates/part/detail.html:136 templates/js/table_filters.js:27
#: part/templates/part/detail.html:138 templates/js/table_filters.js:27
msgid "Virtual"
msgstr "Virtuell"
#: part/templates/part/detail.html:139
#: part/templates/part/detail.html:141
msgid "Part is virtual (not a physical part)"
msgstr "Teil ist virtuell (kein physisches Teil)"
#: part/templates/part/detail.html:141
#: part/templates/part/detail.html:143
msgid "Part is not a virtual part"
msgstr "Teil ist nicht virtuell"
#: part/templates/part/detail.html:145 stock/forms.py:248
#: part/templates/part/detail.html:148 stock/forms.py:248
#: templates/js/table_filters.js:23 templates/js/table_filters.js:243
msgid "Template"
msgstr "Vorlage"
#: part/templates/part/detail.html:148
#: part/templates/part/detail.html:151
#, 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:150
#: part/templates/part/detail.html:153
#, 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:154 templates/js/table_filters.js:255
#: part/templates/part/detail.html:158 templates/js/table_filters.js:255
msgid "Assembly"
msgstr "Baugruppe"
#: part/templates/part/detail.html:157
#: part/templates/part/detail.html:161
msgid "Part can be assembled from other parts"
msgstr "Teil kann aus anderen Teilen angefertigt werden"
#: part/templates/part/detail.html:159
#: part/templates/part/detail.html:163
msgid "Part cannot be assembled from other parts"
msgstr "Teil kann nicht aus anderen Teilen angefertigt werden"
#: part/templates/part/detail.html:163 templates/js/table_filters.js:259
#: part/templates/part/detail.html:168 templates/js/table_filters.js:259
msgid "Component"
msgstr "Komponente"
#: part/templates/part/detail.html:166
#: part/templates/part/detail.html:171
msgid "Part can be used in assemblies"
msgstr "Teil kann in Baugruppen benutzt werden"
#: part/templates/part/detail.html:168
#: part/templates/part/detail.html:173
msgid "Part cannot be used in assemblies"
msgstr "Teil kann nicht in Baugruppen benutzt werden"
#: part/templates/part/detail.html:172 templates/js/table_filters.js:31
#: part/templates/part/detail.html:178 templates/js/table_filters.js:31
#: templates/js/table_filters.js:271
msgid "Trackable"
msgstr "nachverfolgbar"
#: part/templates/part/detail.html:175
#: part/templates/part/detail.html:181
msgid "Part stock is tracked by serial number"
msgstr "Teilebestand in der Seriennummer hinterlegt"
#: part/templates/part/detail.html:177
#: part/templates/part/detail.html:183
msgid "Part stock is not tracked by serial number"
msgstr "Teilebestand ist nicht in der Seriennummer hinterlegt"
#: part/templates/part/detail.html:181
#: part/templates/part/detail.html:188
msgid "Purchaseable"
msgstr "Kaufbar"
#: part/templates/part/detail.html:184 part/templates/part/detail.html:186
#: part/templates/part/detail.html:191 part/templates/part/detail.html:193
msgid "Part can be purchased from external suppliers"
msgstr "Teil kann von externen Zulieferern gekauft werden"
#: part/templates/part/detail.html:190 templates/js/table_filters.js:267
#: part/templates/part/detail.html:198 templates/js/table_filters.js:267
msgid "Salable"
msgstr "Verkäuflich"
#: part/templates/part/detail.html:193
#: part/templates/part/detail.html:201
msgid "Part can be sold to customers"
msgstr "Teil kann an Kunden verkauft werden"
#: part/templates/part/detail.html:195
#: part/templates/part/detail.html:203
msgid "Part cannot be sold to customers"
msgstr "Teil kann nicht an Kunden verkauft werden"
#: part/templates/part/detail.html:199 templates/js/table_filters.js:19
#: part/templates/part/detail.html:214 templates/js/table_filters.js:19
#: templates/js/table_filters.js:55 templates/js/table_filters.js:238
msgid "Active"
msgstr "Aktiv"
#: part/templates/part/detail.html:202
#: part/templates/part/detail.html:217
#, fuzzy
#| msgid "This part is not active"
msgid "Part is active"
msgstr "Dieses Teil ist nicht aktiv"
#: part/templates/part/detail.html:204
#: part/templates/part/detail.html:219
#, fuzzy
#| msgid "This part is not active"
msgid "Part is not active"
@ -3344,99 +3379,111 @@ msgstr "Teilbild nicht gefunden"
msgid "Edit Part Properties"
msgstr "Teileigenschaften bearbeiten"
#: part/views.py:838
#: part/views.py:841
#, fuzzy
#| msgid "Duplicate Part"
msgid "Duplicate BOM"
msgstr "Teil duplizieren"
#: part/views.py:871
#, fuzzy
#| msgid "Confirm unallocation of build stock"
msgid "Confirm duplication of BOM from parent"
msgstr "Zuweisungsaufhebung bestätigen"
#: part/views.py:887
msgid "Validate BOM"
msgstr "BOM validieren"
#: part/views.py:1005
#: part/views.py:1054
msgid "No BOM file provided"
msgstr "Keine Stückliste angegeben"
#: part/views.py:1355
#: part/views.py:1404
msgid "Enter a valid quantity"
msgstr "Bitte eine gültige Anzahl eingeben"
#: part/views.py:1380 part/views.py:1383
#: part/views.py:1429 part/views.py:1432
msgid "Select valid part"
msgstr "Bitte ein gültiges Teil auswählen"
#: part/views.py:1389
#: part/views.py:1438
msgid "Duplicate part selected"
msgstr "Teil doppelt ausgewählt"
#: part/views.py:1427
#: part/views.py:1476
msgid "Select a part"
msgstr "Teil auswählen"
#: part/views.py:1433
#: part/views.py:1482
#, fuzzy
#| msgid "Select part to be used in BOM"
msgid "Selected part creates a circular BOM"
msgstr "Teil für die Nutzung in der Stückliste auswählen"
#: part/views.py:1437
#: part/views.py:1486
msgid "Specify quantity"
msgstr "Anzahl angeben"
#: part/views.py:1693
#: part/views.py:1742
msgid "Confirm Part Deletion"
msgstr "Löschen des Teils bestätigen"
#: part/views.py:1702
#: part/views.py:1751
msgid "Part was deleted"
msgstr "Teil wurde gelöscht"
#: part/views.py:1711
#: part/views.py:1760
msgid "Part Pricing"
msgstr "Teilbepreisung"
#: part/views.py:1837
#: part/views.py:1886
msgid "Create Part Parameter Template"
msgstr "Teilparametervorlage anlegen"
#: part/views.py:1847
#: part/views.py:1896
msgid "Edit Part Parameter Template"
msgstr "Teilparametervorlage bearbeiten"
#: part/views.py:1856
#: part/views.py:1905
msgid "Delete Part Parameter Template"
msgstr "Teilparametervorlage löschen"
#: part/views.py:1866
#: part/views.py:1915
msgid "Create Part Parameter"
msgstr "Teilparameter anlegen"
#: part/views.py:1918
#: part/views.py:1967
msgid "Edit Part Parameter"
msgstr "Teilparameter bearbeiten"
#: part/views.py:1934
#: part/views.py:1983
msgid "Delete Part Parameter"
msgstr "Teilparameter löschen"
#: part/views.py:1993
#: part/views.py:2042
msgid "Edit Part Category"
msgstr "Teilkategorie bearbeiten"
#: part/views.py:2030
#: part/views.py:2079
msgid "Delete Part Category"
msgstr "Teilkategorie löschen"
#: part/views.py:2038
#: part/views.py:2087
msgid "Part category was deleted"
msgstr "Teilekategorie wurde gelöscht"
#: part/views.py:2101
#: part/views.py:2150
#, fuzzy
#| msgid "Create BOM item"
msgid "Create BOM Item"
msgstr "BOM-Position anlegen"
#: part/views.py:2169
#: part/views.py:2218
msgid "Edit BOM item"
msgstr "BOM-Position beaarbeiten"
#: part/views.py:2219
#: part/views.py:2268
msgid "Confim BOM item deletion"
msgstr "Löschung von BOM-Position bestätigen"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-29 02:25+0000\n"
"POT-Creation-Date: 2020-10-29 23:05+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -204,7 +204,7 @@ msgstr ""
msgid "Overage must be an integer value or a percentage"
msgstr ""
#: InvenTree/views.py:707
#: InvenTree/views.py:752
msgid "Database Statistics"
msgstr ""
@ -520,7 +520,7 @@ msgstr ""
msgid "No BOM items found"
msgstr ""
#: build/templates/build/allocate.html:347 part/models.py:1401
#: build/templates/build/allocate.html:347 part/models.py:1425
#: templates/js/part.js:569 templates/js/table_filters.js:167
msgid "Required"
msgstr ""
@ -1192,7 +1192,7 @@ msgstr ""
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
#: part/templates/part/bom.html:62 part/templates/part/category.html:112
#: part/templates/part/bom.html:67 part/templates/part/category.html:112
#: part/templates/part/category.html:126 part/templates/part/stock.html:51
#: templates/stock_table.html:7
msgid "Export"
@ -1310,7 +1310,7 @@ msgid "Pricing Information"
msgstr ""
#: company/templates/company/supplier_part_pricing.html:17 company/views.py:410
#: part/templates/part/sale_prices.html:13 part/views.py:2229
#: part/templates/part/sale_prices.html:13 part/views.py:2278
msgid "Add Price Break"
msgstr ""
@ -1437,15 +1437,15 @@ msgstr ""
msgid "Delete Supplier Part"
msgstr ""
#: company/views.py:416 part/views.py:2235
#: company/views.py:416 part/views.py:2284
msgid "Added new price break"
msgstr ""
#: company/views.py:453 part/views.py:2280
#: company/views.py:453 part/views.py:2329
msgid "Edit Price Break"
msgstr ""
#: company/views.py:469 part/views.py:2296
#: company/views.py:469 part/views.py:2345
msgid "Delete Price Break"
msgstr ""
@ -1538,7 +1538,7 @@ msgstr ""
msgid "Date order was completed"
msgstr ""
#: order/models.py:185 order/models.py:259 part/views.py:1346
#: order/models.py:185 order/models.py:259 part/views.py:1395
#: stock/models.py:241 stock/models.py:805
msgid "Quantity must be greater than zero"
msgstr ""
@ -1815,6 +1815,7 @@ msgstr ""
#: order/templates/order/sales_order_cancel.html:8
#: order/templates/order/sales_order_ship.html:9
#: part/templates/part/bom_duplicate.html:12
#: stock/templates/stock/stockitem_convert.html:13
msgid "Warning"
msgstr ""
@ -2039,91 +2040,107 @@ msgstr ""
msgid "Error reading BOM file (incorrect row size)"
msgstr ""
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "File Format"
msgstr ""
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "Select output file format"
msgstr ""
#: part/forms.py:59
#: part/forms.py:64
msgid "Cascading"
msgstr ""
#: part/forms.py:59
#: part/forms.py:64
msgid "Download cascading / multi-level BOM"
msgstr ""
#: part/forms.py:61
#: part/forms.py:66
msgid "Levels"
msgstr ""
#: part/forms.py:61
#: part/forms.py:66
msgid "Select maximum number of BOM levels to export (0 = all levels)"
msgstr ""
#: part/forms.py:63
#: part/forms.py:68
msgid "Include Parameter Data"
msgstr ""
#: part/forms.py:63
#: part/forms.py:68
msgid "Include part parameters data in exported BOM"
msgstr ""
#: part/forms.py:65
#: part/forms.py:70
msgid "Include Stock Data"
msgstr ""
#: part/forms.py:65
#: part/forms.py:70
msgid "Include part stock data in exported BOM"
msgstr ""
#: part/forms.py:67
#: part/forms.py:72
msgid "Include Supplier Data"
msgstr ""
#: part/forms.py:67
#: part/forms.py:72
msgid "Include part supplier data in exported BOM"
msgstr ""
#: part/forms.py:86
#: part/forms.py:93 part/models.py:1504
msgid "Parent Part"
msgstr ""
#: part/forms.py:94 part/templates/part/bom_duplicate.html:7
msgid "Select parent part to copy BOM from"
msgstr ""
#: part/forms.py:100
msgid "Clear existing BOM items"
msgstr ""
#: part/forms.py:105
msgid "Confirm BOM duplication"
msgstr ""
#: part/forms.py:123
msgid "Confirm that the BOM is correct"
msgstr ""
#: part/forms.py:98
#: part/forms.py:135
msgid "Select BOM file to upload"
msgstr ""
#: part/forms.py:122
#: part/forms.py:159
msgid "Select part category"
msgstr ""
#: part/forms.py:136
#: part/forms.py:173
msgid "Duplicate all BOM data for this part"
msgstr ""
#: part/forms.py:137
#: part/forms.py:174
msgid "Copy BOM"
msgstr ""
#: part/forms.py:142
#: part/forms.py:179
msgid "Duplicate all parameter data for this part"
msgstr ""
#: part/forms.py:143
#: part/forms.py:180
msgid "Copy Parameters"
msgstr ""
#: part/forms.py:148
#: part/forms.py:185
msgid "Confirm part creation"
msgstr ""
#: part/forms.py:248
#: part/forms.py:279
msgid "Input quantity for price calculation"
msgstr ""
#: part/forms.py:251
#: part/forms.py:282
msgid "Select currency for price calculation"
msgstr ""
@ -2249,112 +2266,108 @@ msgstr ""
msgid "Stored BOM checksum"
msgstr ""
#: part/models.py:1353
#: part/models.py:1377
msgid "Test templates can only be created for trackable parts"
msgstr ""
#: part/models.py:1370
#: part/models.py:1394
msgid "Test with this name already exists for this part"
msgstr ""
#: part/models.py:1389 templates/js/part.js:560 templates/js/stock.js:92
#: part/models.py:1413 templates/js/part.js:560 templates/js/stock.js:92
msgid "Test Name"
msgstr ""
#: part/models.py:1390
#: part/models.py:1414
msgid "Enter a name for the test"
msgstr ""
#: part/models.py:1395
#: part/models.py:1419
msgid "Test Description"
msgstr ""
#: part/models.py:1396
#: part/models.py:1420
msgid "Enter description for this test"
msgstr ""
#: part/models.py:1402
#: part/models.py:1426
msgid "Is this test required to pass?"
msgstr ""
#: part/models.py:1407 templates/js/part.js:577
#: part/models.py:1431 templates/js/part.js:577
msgid "Requires Value"
msgstr ""
#: part/models.py:1408
#: part/models.py:1432
msgid "Does this test require a value when adding a test result?"
msgstr ""
#: part/models.py:1413 templates/js/part.js:584
#: part/models.py:1437 templates/js/part.js:584
msgid "Requires Attachment"
msgstr ""
#: part/models.py:1414
#: part/models.py:1438
msgid "Does this test require a file attachment when adding a test result?"
msgstr ""
#: part/models.py:1447
#: part/models.py:1471
msgid "Parameter template name must be unique"
msgstr ""
#: part/models.py:1452
#: part/models.py:1476
msgid "Parameter Name"
msgstr ""
#: part/models.py:1454
#: part/models.py:1478
msgid "Parameter Units"
msgstr ""
#: part/models.py:1480
msgid "Parent Part"
msgstr ""
#: part/models.py:1482
#: part/models.py:1506
msgid "Parameter Template"
msgstr ""
#: part/models.py:1484
#: part/models.py:1508
msgid "Parameter Value"
msgstr ""
#: part/models.py:1521
#: part/models.py:1545
msgid "Select parent part"
msgstr ""
#: part/models.py:1529
#: part/models.py:1553
msgid "Select part to be used in BOM"
msgstr ""
#: part/models.py:1535
#: part/models.py:1559
msgid "BOM quantity for this BOM item"
msgstr ""
#: part/models.py:1537
#: part/models.py:1561
msgid "This BOM item is optional"
msgstr ""
#: part/models.py:1540
#: part/models.py:1564
msgid "Estimated build wastage quantity (absolute or percentage)"
msgstr ""
#: part/models.py:1543
#: part/models.py:1567
msgid "BOM item reference"
msgstr ""
#: part/models.py:1546
#: part/models.py:1570
msgid "BOM item notes"
msgstr ""
#: part/models.py:1548
#: part/models.py:1572
msgid "BOM line checksum"
msgstr ""
#: part/models.py:1612 part/views.py:1352 part/views.py:1404
#: part/models.py:1636 part/views.py:1401 part/views.py:1453
#: stock/models.py:231
msgid "Quantity must be integer value for trackable parts"
msgstr ""
#: part/models.py:1621
#: part/models.py:1645
msgid "BOM Item"
msgstr ""
@ -2396,54 +2409,66 @@ msgid "Import BOM data"
msgstr ""
#: part/templates/part/bom.html:42
msgid "Upload"
msgstr ""
#: part/templates/part/bom.html:44
msgid "New BOM Item"
msgid "Import from File"
msgstr ""
#: part/templates/part/bom.html:45
msgid "Copy BOM from parent part"
msgstr ""
#: part/templates/part/bom.html:46
msgid "Copy from Parent"
msgstr ""
#: part/templates/part/bom.html:49
msgid "New BOM Item"
msgstr ""
#: part/templates/part/bom.html:50
msgid "Add Item"
msgstr ""
#: part/templates/part/bom.html:47
#: part/templates/part/bom.html:52
msgid "Finish Editing"
msgstr ""
#: part/templates/part/bom.html:48
#: part/templates/part/bom.html:53
msgid "Finished"
msgstr ""
#: part/templates/part/bom.html:52
#: part/templates/part/bom.html:57
msgid "Edit BOM"
msgstr ""
#: part/templates/part/bom.html:53 part/templates/part/params.html:38
#: part/templates/part/bom.html:58 part/templates/part/params.html:38
#: templates/InvenTree/settings/user.html:19
msgid "Edit"
msgstr ""
#: part/templates/part/bom.html:56
#: part/templates/part/bom.html:61
msgid "Validate Bill of Materials"
msgstr ""
#: part/templates/part/bom.html:57
#: part/templates/part/bom.html:62
msgid "Validate"
msgstr ""
#: part/templates/part/bom.html:61 part/views.py:1643
#: part/templates/part/bom.html:66 part/views.py:1692
msgid "Export Bill of Materials"
msgstr ""
#: part/templates/part/bom.html:122
#: part/templates/part/bom.html:127
msgid "Delete selected BOM items?"
msgstr ""
#: part/templates/part/bom.html:123
#: part/templates/part/bom.html:128
msgid "All selected BOM items will be deleted"
msgstr ""
#: part/templates/part/bom_duplicate.html:13
msgid "This part already has a Bill of Materials"
msgstr ""
#: part/templates/part/bom_upload/select_fields.html:8
#: part/templates/part/bom_upload/select_parts.html:8
#: part/templates/part/bom_upload/upload_file.html:10
@ -2524,7 +2549,7 @@ msgstr ""
msgid "All parts"
msgstr ""
#: part/templates/part/category.html:24 part/views.py:2046
#: part/templates/part/category.html:24 part/views.py:2095
msgid "Create new part category"
msgstr ""
@ -2670,98 +2695,98 @@ msgstr ""
msgid "Responsible User"
msgstr ""
#: part/templates/part/detail.html:136 templates/js/table_filters.js:27
#: part/templates/part/detail.html:138 templates/js/table_filters.js:27
msgid "Virtual"
msgstr ""
#: part/templates/part/detail.html:139
#: part/templates/part/detail.html:141
msgid "Part is virtual (not a physical part)"
msgstr ""
#: part/templates/part/detail.html:141
#: part/templates/part/detail.html:143
msgid "Part is not a virtual part"
msgstr ""
#: part/templates/part/detail.html:145 stock/forms.py:248
#: part/templates/part/detail.html:148 stock/forms.py:248
#: templates/js/table_filters.js:23 templates/js/table_filters.js:243
msgid "Template"
msgstr ""
#: part/templates/part/detail.html:148
#: part/templates/part/detail.html:151
msgid "Part is a template part (variants can be made from this part)"
msgstr ""
#: part/templates/part/detail.html:150
#: part/templates/part/detail.html:153
msgid "Part is not a template part"
msgstr ""
#: part/templates/part/detail.html:154 templates/js/table_filters.js:255
#: part/templates/part/detail.html:158 templates/js/table_filters.js:255
msgid "Assembly"
msgstr ""
#: part/templates/part/detail.html:157
#: part/templates/part/detail.html:161
msgid "Part can be assembled from other parts"
msgstr ""
#: part/templates/part/detail.html:159
#: part/templates/part/detail.html:163
msgid "Part cannot be assembled from other parts"
msgstr ""
#: part/templates/part/detail.html:163 templates/js/table_filters.js:259
#: part/templates/part/detail.html:168 templates/js/table_filters.js:259
msgid "Component"
msgstr ""
#: part/templates/part/detail.html:166
#: part/templates/part/detail.html:171
msgid "Part can be used in assemblies"
msgstr ""
#: part/templates/part/detail.html:168
#: part/templates/part/detail.html:173
msgid "Part cannot be used in assemblies"
msgstr ""
#: part/templates/part/detail.html:172 templates/js/table_filters.js:31
#: part/templates/part/detail.html:178 templates/js/table_filters.js:31
#: templates/js/table_filters.js:271
msgid "Trackable"
msgstr ""
#: part/templates/part/detail.html:175
#: part/templates/part/detail.html:181
msgid "Part stock is tracked by serial number"
msgstr ""
#: part/templates/part/detail.html:177
#: part/templates/part/detail.html:183
msgid "Part stock is not tracked by serial number"
msgstr ""
#: part/templates/part/detail.html:181
#: part/templates/part/detail.html:188
msgid "Purchaseable"
msgstr ""
#: part/templates/part/detail.html:184 part/templates/part/detail.html:186
#: part/templates/part/detail.html:191 part/templates/part/detail.html:193
msgid "Part can be purchased from external suppliers"
msgstr ""
#: part/templates/part/detail.html:190 templates/js/table_filters.js:267
#: part/templates/part/detail.html:198 templates/js/table_filters.js:267
msgid "Salable"
msgstr ""
#: part/templates/part/detail.html:193
#: part/templates/part/detail.html:201
msgid "Part can be sold to customers"
msgstr ""
#: part/templates/part/detail.html:195
#: part/templates/part/detail.html:203
msgid "Part cannot be sold to customers"
msgstr ""
#: part/templates/part/detail.html:199 templates/js/table_filters.js:19
#: part/templates/part/detail.html:214 templates/js/table_filters.js:19
#: templates/js/table_filters.js:55 templates/js/table_filters.js:238
msgid "Active"
msgstr ""
#: part/templates/part/detail.html:202
#: part/templates/part/detail.html:217
msgid "Part is active"
msgstr ""
#: part/templates/part/detail.html:204
#: part/templates/part/detail.html:219
msgid "Part is not active"
msgstr ""
@ -3069,95 +3094,103 @@ msgstr ""
msgid "Edit Part Properties"
msgstr ""
#: part/views.py:838
#: part/views.py:841
msgid "Duplicate BOM"
msgstr ""
#: part/views.py:871
msgid "Confirm duplication of BOM from parent"
msgstr ""
#: part/views.py:887
msgid "Validate BOM"
msgstr ""
#: part/views.py:1005
#: part/views.py:1054
msgid "No BOM file provided"
msgstr ""
#: part/views.py:1355
#: part/views.py:1404
msgid "Enter a valid quantity"
msgstr ""
#: part/views.py:1380 part/views.py:1383
#: part/views.py:1429 part/views.py:1432
msgid "Select valid part"
msgstr ""
#: part/views.py:1389
#: part/views.py:1438
msgid "Duplicate part selected"
msgstr ""
#: part/views.py:1427
#: part/views.py:1476
msgid "Select a part"
msgstr ""
#: part/views.py:1433
#: part/views.py:1482
msgid "Selected part creates a circular BOM"
msgstr ""
#: part/views.py:1437
#: part/views.py:1486
msgid "Specify quantity"
msgstr ""
#: part/views.py:1693
#: part/views.py:1742
msgid "Confirm Part Deletion"
msgstr ""
#: part/views.py:1702
#: part/views.py:1751
msgid "Part was deleted"
msgstr ""
#: part/views.py:1711
#: part/views.py:1760
msgid "Part Pricing"
msgstr ""
#: part/views.py:1837
#: part/views.py:1886
msgid "Create Part Parameter Template"
msgstr ""
#: part/views.py:1847
#: part/views.py:1896
msgid "Edit Part Parameter Template"
msgstr ""
#: part/views.py:1856
#: part/views.py:1905
msgid "Delete Part Parameter Template"
msgstr ""
#: part/views.py:1866
#: part/views.py:1915
msgid "Create Part Parameter"
msgstr ""
#: part/views.py:1918
#: part/views.py:1967
msgid "Edit Part Parameter"
msgstr ""
#: part/views.py:1934
#: part/views.py:1983
msgid "Delete Part Parameter"
msgstr ""
#: part/views.py:1993
#: part/views.py:2042
msgid "Edit Part Category"
msgstr ""
#: part/views.py:2030
#: part/views.py:2079
msgid "Delete Part Category"
msgstr ""
#: part/views.py:2038
#: part/views.py:2087
msgid "Part category was deleted"
msgstr ""
#: part/views.py:2101
#: part/views.py:2150
msgid "Create BOM Item"
msgstr ""
#: part/views.py:2169
#: part/views.py:2218
msgid "Edit BOM item"
msgstr ""
#: part/views.py:2219
#: part/views.py:2268
msgid "Confim BOM item deletion"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-29 02:25+0000\n"
"POT-Creation-Date: 2020-10-29 23:05+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -204,7 +204,7 @@ msgstr ""
msgid "Overage must be an integer value or a percentage"
msgstr ""
#: InvenTree/views.py:707
#: InvenTree/views.py:752
msgid "Database Statistics"
msgstr ""
@ -520,7 +520,7 @@ msgstr ""
msgid "No BOM items found"
msgstr ""
#: build/templates/build/allocate.html:347 part/models.py:1401
#: build/templates/build/allocate.html:347 part/models.py:1425
#: templates/js/part.js:569 templates/js/table_filters.js:167
msgid "Required"
msgstr ""
@ -1192,7 +1192,7 @@ msgstr ""
#: company/templates/company/detail_stock.html:35
#: company/templates/company/supplier_part_stock.html:33
#: part/templates/part/bom.html:62 part/templates/part/category.html:112
#: part/templates/part/bom.html:67 part/templates/part/category.html:112
#: part/templates/part/category.html:126 part/templates/part/stock.html:51
#: templates/stock_table.html:7
msgid "Export"
@ -1310,7 +1310,7 @@ msgid "Pricing Information"
msgstr ""
#: company/templates/company/supplier_part_pricing.html:17 company/views.py:410
#: part/templates/part/sale_prices.html:13 part/views.py:2229
#: part/templates/part/sale_prices.html:13 part/views.py:2278
msgid "Add Price Break"
msgstr ""
@ -1437,15 +1437,15 @@ msgstr ""
msgid "Delete Supplier Part"
msgstr ""
#: company/views.py:416 part/views.py:2235
#: company/views.py:416 part/views.py:2284
msgid "Added new price break"
msgstr ""
#: company/views.py:453 part/views.py:2280
#: company/views.py:453 part/views.py:2329
msgid "Edit Price Break"
msgstr ""
#: company/views.py:469 part/views.py:2296
#: company/views.py:469 part/views.py:2345
msgid "Delete Price Break"
msgstr ""
@ -1538,7 +1538,7 @@ msgstr ""
msgid "Date order was completed"
msgstr ""
#: order/models.py:185 order/models.py:259 part/views.py:1346
#: order/models.py:185 order/models.py:259 part/views.py:1395
#: stock/models.py:241 stock/models.py:805
msgid "Quantity must be greater than zero"
msgstr ""
@ -1815,6 +1815,7 @@ msgstr ""
#: order/templates/order/sales_order_cancel.html:8
#: order/templates/order/sales_order_ship.html:9
#: part/templates/part/bom_duplicate.html:12
#: stock/templates/stock/stockitem_convert.html:13
msgid "Warning"
msgstr ""
@ -2039,91 +2040,107 @@ msgstr ""
msgid "Error reading BOM file (incorrect row size)"
msgstr ""
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "File Format"
msgstr ""
#: part/forms.py:57 stock/forms.py:254
#: part/forms.py:62 stock/forms.py:254
msgid "Select output file format"
msgstr ""
#: part/forms.py:59
#: part/forms.py:64
msgid "Cascading"
msgstr ""
#: part/forms.py:59
#: part/forms.py:64
msgid "Download cascading / multi-level BOM"
msgstr ""
#: part/forms.py:61
#: part/forms.py:66
msgid "Levels"
msgstr ""
#: part/forms.py:61
#: part/forms.py:66
msgid "Select maximum number of BOM levels to export (0 = all levels)"
msgstr ""
#: part/forms.py:63
#: part/forms.py:68
msgid "Include Parameter Data"
msgstr ""
#: part/forms.py:63
#: part/forms.py:68
msgid "Include part parameters data in exported BOM"
msgstr ""
#: part/forms.py:65
#: part/forms.py:70
msgid "Include Stock Data"
msgstr ""
#: part/forms.py:65
#: part/forms.py:70
msgid "Include part stock data in exported BOM"
msgstr ""
#: part/forms.py:67
#: part/forms.py:72
msgid "Include Supplier Data"
msgstr ""
#: part/forms.py:67
#: part/forms.py:72
msgid "Include part supplier data in exported BOM"
msgstr ""
#: part/forms.py:86
#: part/forms.py:93 part/models.py:1504
msgid "Parent Part"
msgstr ""
#: part/forms.py:94 part/templates/part/bom_duplicate.html:7
msgid "Select parent part to copy BOM from"
msgstr ""
#: part/forms.py:100
msgid "Clear existing BOM items"
msgstr ""
#: part/forms.py:105
msgid "Confirm BOM duplication"
msgstr ""
#: part/forms.py:123
msgid "Confirm that the BOM is correct"
msgstr ""
#: part/forms.py:98
#: part/forms.py:135
msgid "Select BOM file to upload"
msgstr ""
#: part/forms.py:122
#: part/forms.py:159
msgid "Select part category"
msgstr ""
#: part/forms.py:136
#: part/forms.py:173
msgid "Duplicate all BOM data for this part"
msgstr ""
#: part/forms.py:137
#: part/forms.py:174
msgid "Copy BOM"
msgstr ""
#: part/forms.py:142
#: part/forms.py:179
msgid "Duplicate all parameter data for this part"
msgstr ""
#: part/forms.py:143
#: part/forms.py:180
msgid "Copy Parameters"
msgstr ""
#: part/forms.py:148
#: part/forms.py:185
msgid "Confirm part creation"
msgstr ""
#: part/forms.py:248
#: part/forms.py:279
msgid "Input quantity for price calculation"
msgstr ""
#: part/forms.py:251
#: part/forms.py:282
msgid "Select currency for price calculation"
msgstr ""
@ -2249,112 +2266,108 @@ msgstr ""
msgid "Stored BOM checksum"
msgstr ""
#: part/models.py:1353
#: part/models.py:1377
msgid "Test templates can only be created for trackable parts"
msgstr ""
#: part/models.py:1370
#: part/models.py:1394
msgid "Test with this name already exists for this part"
msgstr ""
#: part/models.py:1389 templates/js/part.js:560 templates/js/stock.js:92
#: part/models.py:1413 templates/js/part.js:560 templates/js/stock.js:92
msgid "Test Name"
msgstr ""
#: part/models.py:1390
#: part/models.py:1414
msgid "Enter a name for the test"
msgstr ""
#: part/models.py:1395
#: part/models.py:1419
msgid "Test Description"
msgstr ""
#: part/models.py:1396
#: part/models.py:1420
msgid "Enter description for this test"
msgstr ""
#: part/models.py:1402
#: part/models.py:1426
msgid "Is this test required to pass?"
msgstr ""
#: part/models.py:1407 templates/js/part.js:577
#: part/models.py:1431 templates/js/part.js:577
msgid "Requires Value"
msgstr ""
#: part/models.py:1408
#: part/models.py:1432
msgid "Does this test require a value when adding a test result?"
msgstr ""
#: part/models.py:1413 templates/js/part.js:584
#: part/models.py:1437 templates/js/part.js:584
msgid "Requires Attachment"
msgstr ""
#: part/models.py:1414
#: part/models.py:1438
msgid "Does this test require a file attachment when adding a test result?"
msgstr ""
#: part/models.py:1447
#: part/models.py:1471
msgid "Parameter template name must be unique"
msgstr ""
#: part/models.py:1452
#: part/models.py:1476
msgid "Parameter Name"
msgstr ""
#: part/models.py:1454
#: part/models.py:1478
msgid "Parameter Units"
msgstr ""
#: part/models.py:1480
msgid "Parent Part"
msgstr ""
#: part/models.py:1482
#: part/models.py:1506
msgid "Parameter Template"
msgstr ""
#: part/models.py:1484
#: part/models.py:1508
msgid "Parameter Value"
msgstr ""
#: part/models.py:1521
#: part/models.py:1545
msgid "Select parent part"
msgstr ""
#: part/models.py:1529
#: part/models.py:1553
msgid "Select part to be used in BOM"
msgstr ""
#: part/models.py:1535
#: part/models.py:1559
msgid "BOM quantity for this BOM item"
msgstr ""
#: part/models.py:1537
#: part/models.py:1561
msgid "This BOM item is optional"
msgstr ""
#: part/models.py:1540
#: part/models.py:1564
msgid "Estimated build wastage quantity (absolute or percentage)"
msgstr ""
#: part/models.py:1543
#: part/models.py:1567
msgid "BOM item reference"
msgstr ""
#: part/models.py:1546
#: part/models.py:1570
msgid "BOM item notes"
msgstr ""
#: part/models.py:1548
#: part/models.py:1572
msgid "BOM line checksum"
msgstr ""
#: part/models.py:1612 part/views.py:1352 part/views.py:1404
#: part/models.py:1636 part/views.py:1401 part/views.py:1453
#: stock/models.py:231
msgid "Quantity must be integer value for trackable parts"
msgstr ""
#: part/models.py:1621
#: part/models.py:1645
msgid "BOM Item"
msgstr ""
@ -2396,54 +2409,66 @@ msgid "Import BOM data"
msgstr ""
#: part/templates/part/bom.html:42
msgid "Upload"
msgstr ""
#: part/templates/part/bom.html:44
msgid "New BOM Item"
msgid "Import from File"
msgstr ""
#: part/templates/part/bom.html:45
msgid "Copy BOM from parent part"
msgstr ""
#: part/templates/part/bom.html:46
msgid "Copy from Parent"
msgstr ""
#: part/templates/part/bom.html:49
msgid "New BOM Item"
msgstr ""
#: part/templates/part/bom.html:50
msgid "Add Item"
msgstr ""
#: part/templates/part/bom.html:47
#: part/templates/part/bom.html:52
msgid "Finish Editing"
msgstr ""
#: part/templates/part/bom.html:48
#: part/templates/part/bom.html:53
msgid "Finished"
msgstr ""
#: part/templates/part/bom.html:52
#: part/templates/part/bom.html:57
msgid "Edit BOM"
msgstr ""
#: part/templates/part/bom.html:53 part/templates/part/params.html:38
#: part/templates/part/bom.html:58 part/templates/part/params.html:38
#: templates/InvenTree/settings/user.html:19
msgid "Edit"
msgstr ""
#: part/templates/part/bom.html:56
#: part/templates/part/bom.html:61
msgid "Validate Bill of Materials"
msgstr ""
#: part/templates/part/bom.html:57
#: part/templates/part/bom.html:62
msgid "Validate"
msgstr ""
#: part/templates/part/bom.html:61 part/views.py:1643
#: part/templates/part/bom.html:66 part/views.py:1692
msgid "Export Bill of Materials"
msgstr ""
#: part/templates/part/bom.html:122
#: part/templates/part/bom.html:127
msgid "Delete selected BOM items?"
msgstr ""
#: part/templates/part/bom.html:123
#: part/templates/part/bom.html:128
msgid "All selected BOM items will be deleted"
msgstr ""
#: part/templates/part/bom_duplicate.html:13
msgid "This part already has a Bill of Materials"
msgstr ""
#: part/templates/part/bom_upload/select_fields.html:8
#: part/templates/part/bom_upload/select_parts.html:8
#: part/templates/part/bom_upload/upload_file.html:10
@ -2524,7 +2549,7 @@ msgstr ""
msgid "All parts"
msgstr ""
#: part/templates/part/category.html:24 part/views.py:2046
#: part/templates/part/category.html:24 part/views.py:2095
msgid "Create new part category"
msgstr ""
@ -2670,98 +2695,98 @@ msgstr ""
msgid "Responsible User"
msgstr ""
#: part/templates/part/detail.html:136 templates/js/table_filters.js:27
#: part/templates/part/detail.html:138 templates/js/table_filters.js:27
msgid "Virtual"
msgstr ""
#: part/templates/part/detail.html:139
#: part/templates/part/detail.html:141
msgid "Part is virtual (not a physical part)"
msgstr ""
#: part/templates/part/detail.html:141
#: part/templates/part/detail.html:143
msgid "Part is not a virtual part"
msgstr ""
#: part/templates/part/detail.html:145 stock/forms.py:248
#: part/templates/part/detail.html:148 stock/forms.py:248
#: templates/js/table_filters.js:23 templates/js/table_filters.js:243
msgid "Template"
msgstr ""
#: part/templates/part/detail.html:148
#: part/templates/part/detail.html:151
msgid "Part is a template part (variants can be made from this part)"
msgstr ""
#: part/templates/part/detail.html:150
#: part/templates/part/detail.html:153
msgid "Part is not a template part"
msgstr ""
#: part/templates/part/detail.html:154 templates/js/table_filters.js:255
#: part/templates/part/detail.html:158 templates/js/table_filters.js:255
msgid "Assembly"
msgstr ""
#: part/templates/part/detail.html:157
#: part/templates/part/detail.html:161
msgid "Part can be assembled from other parts"
msgstr ""
#: part/templates/part/detail.html:159
#: part/templates/part/detail.html:163
msgid "Part cannot be assembled from other parts"
msgstr ""
#: part/templates/part/detail.html:163 templates/js/table_filters.js:259
#: part/templates/part/detail.html:168 templates/js/table_filters.js:259
msgid "Component"
msgstr ""
#: part/templates/part/detail.html:166
#: part/templates/part/detail.html:171
msgid "Part can be used in assemblies"
msgstr ""
#: part/templates/part/detail.html:168
#: part/templates/part/detail.html:173
msgid "Part cannot be used in assemblies"
msgstr ""
#: part/templates/part/detail.html:172 templates/js/table_filters.js:31
#: part/templates/part/detail.html:178 templates/js/table_filters.js:31
#: templates/js/table_filters.js:271
msgid "Trackable"
msgstr ""
#: part/templates/part/detail.html:175
#: part/templates/part/detail.html:181
msgid "Part stock is tracked by serial number"
msgstr ""
#: part/templates/part/detail.html:177
#: part/templates/part/detail.html:183
msgid "Part stock is not tracked by serial number"
msgstr ""
#: part/templates/part/detail.html:181
#: part/templates/part/detail.html:188
msgid "Purchaseable"
msgstr ""
#: part/templates/part/detail.html:184 part/templates/part/detail.html:186
#: part/templates/part/detail.html:191 part/templates/part/detail.html:193
msgid "Part can be purchased from external suppliers"
msgstr ""
#: part/templates/part/detail.html:190 templates/js/table_filters.js:267
#: part/templates/part/detail.html:198 templates/js/table_filters.js:267
msgid "Salable"
msgstr ""
#: part/templates/part/detail.html:193
#: part/templates/part/detail.html:201
msgid "Part can be sold to customers"
msgstr ""
#: part/templates/part/detail.html:195
#: part/templates/part/detail.html:203
msgid "Part cannot be sold to customers"
msgstr ""
#: part/templates/part/detail.html:199 templates/js/table_filters.js:19
#: part/templates/part/detail.html:214 templates/js/table_filters.js:19
#: templates/js/table_filters.js:55 templates/js/table_filters.js:238
msgid "Active"
msgstr ""
#: part/templates/part/detail.html:202
#: part/templates/part/detail.html:217
msgid "Part is active"
msgstr ""
#: part/templates/part/detail.html:204
#: part/templates/part/detail.html:219
msgid "Part is not active"
msgstr ""
@ -3069,95 +3094,103 @@ msgstr ""
msgid "Edit Part Properties"
msgstr ""
#: part/views.py:838
#: part/views.py:841
msgid "Duplicate BOM"
msgstr ""
#: part/views.py:871
msgid "Confirm duplication of BOM from parent"
msgstr ""
#: part/views.py:887
msgid "Validate BOM"
msgstr ""
#: part/views.py:1005
#: part/views.py:1054
msgid "No BOM file provided"
msgstr ""
#: part/views.py:1355
#: part/views.py:1404
msgid "Enter a valid quantity"
msgstr ""
#: part/views.py:1380 part/views.py:1383
#: part/views.py:1429 part/views.py:1432
msgid "Select valid part"
msgstr ""
#: part/views.py:1389
#: part/views.py:1438
msgid "Duplicate part selected"
msgstr ""
#: part/views.py:1427
#: part/views.py:1476
msgid "Select a part"
msgstr ""
#: part/views.py:1433
#: part/views.py:1482
msgid "Selected part creates a circular BOM"
msgstr ""
#: part/views.py:1437
#: part/views.py:1486
msgid "Specify quantity"
msgstr ""
#: part/views.py:1693
#: part/views.py:1742
msgid "Confirm Part Deletion"
msgstr ""
#: part/views.py:1702
#: part/views.py:1751
msgid "Part was deleted"
msgstr ""
#: part/views.py:1711
#: part/views.py:1760
msgid "Part Pricing"
msgstr ""
#: part/views.py:1837
#: part/views.py:1886
msgid "Create Part Parameter Template"
msgstr ""
#: part/views.py:1847
#: part/views.py:1896
msgid "Edit Part Parameter Template"
msgstr ""
#: part/views.py:1856
#: part/views.py:1905
msgid "Delete Part Parameter Template"
msgstr ""
#: part/views.py:1866
#: part/views.py:1915
msgid "Create Part Parameter"
msgstr ""
#: part/views.py:1918
#: part/views.py:1967
msgid "Edit Part Parameter"
msgstr ""
#: part/views.py:1934
#: part/views.py:1983
msgid "Delete Part Parameter"
msgstr ""
#: part/views.py:1993
#: part/views.py:2042
msgid "Edit Part Category"
msgstr ""
#: part/views.py:2030
#: part/views.py:2079
msgid "Delete Part Category"
msgstr ""
#: part/views.py:2038
#: part/views.py:2087
msgid "Part category was deleted"
msgstr ""
#: part/views.py:2101
#: part/views.py:2150
msgid "Create BOM Item"
msgstr ""
#: part/views.py:2169
#: part/views.py:2218
msgid "Edit BOM item"
msgstr ""
#: part/views.py:2219
#: part/views.py:2268
msgid "Confim BOM item deletion"
msgstr ""

View File

@ -100,9 +100,9 @@ class PurchaseOrderAttachmentCreate(AjaxCreateView):
ajax_template_name = "modal_form.html"
role_required = 'purchase_order.add'
def post_save(self, **kwargs):
self.object.user = self.request.user
self.object.save()
def post_save(self, attachment, form, **kwargs):
attachment.user = self.request.user
attachment.save()
def get_data(self):
return {
@ -148,7 +148,7 @@ class SalesOrderAttachmentCreate(AjaxCreateView):
ajax_form_title = _('Add Sales Order Attachment')
role_required = 'sales_order.add'
def post_save(self, **kwargs):
def post_save(self, attachment, form, **kwargs):
self.object.user = self.request.user
self.object.save()
@ -319,11 +319,11 @@ class PurchaseOrderCreate(AjaxCreateView):
return initials
def post_save(self, **kwargs):
def post_save(self, order, form, **kwargs):
# Record the user who created this purchase order
self.object.created_by = self.request.user
self.object.save()
order.created_by = self.request.user
order.save()
class SalesOrderCreate(AjaxCreateView):
@ -351,10 +351,10 @@ class SalesOrderCreate(AjaxCreateView):
return initials
def post_save(self, **kwargs):
def post_save(self, order, form, **kwargs):
# Record the user who created this sales order
self.object.created_by = self.request.user
self.object.save()
order.created_by = self.request.user
order.save()
class PurchaseOrderEdit(AjaxUpdateView):

View File

@ -19,10 +19,15 @@ from .models import PartParameterTemplate, PartParameter
from .models import PartTestTemplate
from .models import PartSellPriceBreak
from common.models import Currency
class PartModelChoiceField(forms.ModelChoiceField):
""" Extending string representation of Part instance with available stock """
def label_from_instance(self, part):
return f'{part} - {part.available_stock}'
class PartImageForm(HelperForm):
""" Form for uploading a Part image """
@ -77,6 +82,38 @@ class BomExportForm(forms.Form):
self.fields['file_format'].choices = self.get_choices()
class BomDuplicateForm(HelperForm):
"""
Simple confirmation form for BOM duplication.
Select which parent to select from.
"""
parent = PartModelChoiceField(
label=_('Parent Part'),
help_text=_('Select parent part to copy BOM from'),
queryset=Part.objects.filter(is_template=True),
)
clear = forms.BooleanField(
required=False, initial=True,
help_text=_('Clear existing BOM items')
)
confirm = forms.BooleanField(
required=False, initial=False,
help_text=_('Confirm BOM duplication')
)
class Meta:
model = Part
fields = [
'parent',
'clear',
'confirm',
]
class BomValidateForm(HelperForm):
""" Simple confirmation form for BOM validation.
User is presented with a single checkbox input,
@ -210,12 +247,6 @@ class EditCategoryForm(HelperForm):
]
class PartModelChoiceField(forms.ModelChoiceField):
""" Extending string representation of Part instance with available stock """
def label_from_instance(self, part):
return f'{part} - {part.available_stock}'
class EditBomItemForm(HelperForm):
""" Form for editing a BomItem object """

View File

@ -1087,6 +1087,35 @@ class Part(MPTTModel):
max(buy_price_range[1], bom_price_range[1])
)
@transaction.atomic
def copy_bom_from(self, other, clear=True, **kwargs):
"""
Copy the BOM from another part.
args:
other - The part to copy the BOM from
clear - Remove existing BOM items first (default=True)
"""
if clear:
# Remove existing BOM items
self.bom_items.all().delete()
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!
try:
existing = BomItem.objects.get(part=self, sub_part=bom_item.sub_part)
existing.delete()
except (BomItem.DoesNotExist):
pass
bom_item.part = self
bom_item.pk = None
bom_item.save()
def deepCopy(self, other, **kwargs):
""" Duplicates non-field data from another part.
Does not alter the normal fields of this part,
@ -1106,12 +1135,7 @@ class Part(MPTTModel):
# Copy the BOM data
if kwargs.get('bom', False):
for item in other.bom_items.all():
# Point the item to THIS part.
# Set the pk to None so a new entry is created.
item.part = self
item.pk = None
item.save()
self.copy_bom_from(other)
# Copy the parameters data
if kwargs.get('parameters', True):

View File

@ -39,8 +39,13 @@
<span class='fas fa-trash-alt'></span>
</button>
<button class='btn btn-primary' type='button' title='{% trans "Import BOM data" %}' id='bom-upload'>
<span class='fas fa-file-upload'></span> {% trans "Upload" %}
<span class='fas fa-file-upload'></span> {% trans "Import from File" %}
</button>
{% if part.variant_of %}
<button class='btn btn-default' type='button' title='{% trans "Copy BOM from parent part" %}' id='bom-duplicate'>
<span class='fas fa-clone'></span> {% trans "Copy from Parent" %}
</button>
{% endif %}
<button class='btn btn-default' type='button' title='{% trans "New BOM Item" %}' id='bom-item-new'>
<span class='fas fa-plus-circle'></span> {% trans "Add Item" %}
</button>
@ -157,6 +162,17 @@
location.href = "{% url 'upload-bom' part.id %}";
});
$('#bom-duplicate').click(function() {
launchModalForm(
"{% url 'duplicate-bom' part.id %}",
{
success: function() {
$('#bom-table').bootstrapTable('refresh');
}
}
);
});
$("#bom-item-new").click(function () {
launchModalForm(
"{% url 'bom-item-create' %}?parent={{ part.id }}",

View File

@ -0,0 +1,17 @@
{% extends "modal_form.html" %}
{% load i18n %}
{% block pre_form_content %}
<p>
{% trans "Select parent part to copy BOM from" %}
</p>
{% if part.has_bom %}
<div class='alert alert-block alert-danger'>
<b>{% trans "Warning" %}</b><br>
{% trans "This part already has a Bill of Materials" %}<br>
</div>
{% endif %}
{% endblock %}

View File

@ -46,6 +46,7 @@ part_detail_urls = [
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'),
url(r'^params/', views.PartDetail.as_view(template_name='part/params.html'), name='part-params'),
url(r'^variants/?', views.PartDetail.as_view(template_name='part/variants.html'), name='part-variants'),

View File

@ -831,8 +831,60 @@ class PartEdit(AjaxUpdateView):
return form
class BomDuplicate(AjaxUpdateView):
"""
View for duplicating BOM from a parent item.
"""
model = Part
context_object_name = 'part'
ajax_form_title = _('Duplicate BOM')
ajax_template_name = 'part/bom_duplicate.html'
form_class = part_forms.BomDuplicateForm
role_required = 'part.change'
def get_form(self):
form = super().get_form()
# Limit choices to parents of the current part
parents = self.get_object().get_ancestors()
form.fields['parent'].queryset = parents
return form
def get_initial(self):
initials = super().get_initial()
parents = self.get_object().get_ancestors()
if parents.count() == 1:
initials['parent'] = parents[0]
return initials
def validate(self, part, form):
confirm = str2bool(form.cleaned_data.get('confirm', False))
if not confirm:
form.add_error('confirm', _('Confirm duplication of BOM from parent'))
def post_save(self, part, form):
parent = form.cleaned_data.get('parent', None)
clear = str2bool(form.cleaned_data.get('clear', True))
if parent:
part.copy_bom_from(parent, clear=clear)
class BomValidate(AjaxUpdateView):
""" Modal form view for validating a part BOM """
"""
Modal form view for validating a part BOM
"""
model = Part
ajax_form_title = _("Validate BOM")

View File

@ -164,11 +164,11 @@ class StockItemAttachmentCreate(AjaxCreateView):
ajax_template_name = "modal_form.html"
role_required = 'stock.add'
def post_save(self, **kwargs):
def post_save(self, attachment, form, **kwargs):
""" Record the user that uploaded the attachment """
self.object.user = self.request.user
self.object.save()
attachment.user = self.request.user
attachment.save()
def get_data(self):
return {
@ -440,11 +440,11 @@ class StockItemTestResultCreate(AjaxCreateView):
ajax_form_title = _("Add Test Result")
role_required = 'stock.add'
def post_save(self, **kwargs):
def post_save(self, result, form, **kwargs):
""" Record the user that uploaded the test result """
self.object.user = self.request.user
self.object.save()
result.user = self.request.user
result.save()
def get_initial(self):