diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 231423be8f..5ede677b9f 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -52,6 +52,24 @@ def str2bool(text, test=True): return str(text).lower() in ['0', 'n', 'no', 'none', 'f', 'false', 'off', ] +def decimal2string(d): + """ + Format a Decimal number as a string, + stripping out any trailing zeroes or decimal points. + Essentially make it look like a whole number if it is one. + + Args: + d: A python Decimal object + + Returns: + A string representation of the input number + """ + + s = str(d) + + return s.rstrip("0").rstrip(".") + + def WrapWithQuotes(text, quote='"'): """ Wrap the supplied text with quotes diff --git a/InvenTree/InvenTree/static/script/inventree/bom.js b/InvenTree/InvenTree/static/script/inventree/bom.js index 97dca94017..e62c8c22f4 100644 --- a/InvenTree/InvenTree/static/script/inventree/bom.js +++ b/InvenTree/InvenTree/static/script/inventree/bom.js @@ -163,21 +163,16 @@ function loadBomTable(table, options) { formatter: function(value, row, index, field) { var text = value; + // The 'value' is a text string with (potentially) multiple trailing zeros + // Let's make it a bit more pretty + text = parseFloat(text); + if (row.overage) { text += " (+" + row.overage + ") "; } return text; }, - footerFormatter: function(data) { - var quantity = 0; - - data.forEach(function(item) { - quantity += item.quantity; - }); - - return quantity; - }, }); if (!options.editable) { diff --git a/InvenTree/InvenTree/static/script/inventree/part.js b/InvenTree/InvenTree/static/script/inventree/part.js index 0904c22a0d..8ad934760b 100644 --- a/InvenTree/InvenTree/static/script/inventree/part.js +++ b/InvenTree/InvenTree/static/script/inventree/part.js @@ -183,6 +183,11 @@ function loadPartTable(table, url, options={}) { sortable: true, formatter: function(value, row, index, field) { if (value) { + + if (row.units) { + value += ' ' + row.units + ''; + } + return renderLink(value, '/part/' + row.pk + '/stock/'); } else { diff --git a/InvenTree/InvenTree/static/script/inventree/stock.js b/InvenTree/InvenTree/static/script/inventree/stock.js index 4fffc961c7..612c8b5c88 100644 --- a/InvenTree/InvenTree/static/script/inventree/stock.js +++ b/InvenTree/InvenTree/static/script/inventree/stock.js @@ -80,6 +80,8 @@ function loadStockTable(table, options) { items += 1; }); + stock = +stock.toFixed(5); + return stock + " (" + items + " items)"; } else if (field == 'batch') { var batches = []; diff --git a/InvenTree/build/migrations/0007_auto_20191118_2321.py b/InvenTree/build/migrations/0007_auto_20191118_2321.py new file mode 100644 index 0000000000..da6b455f60 --- /dev/null +++ b/InvenTree/build/migrations/0007_auto_20191118_2321.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:21 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('build', '0006_auto_20190913_1407'), + ] + + operations = [ + migrations.AlterField( + model_name='builditem', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, help_text='Stock quantity to allocate to build', max_digits=15, validators=[django.core.validators.MinValueValidator(1)]), + ), + ] diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 57792340e8..51e1b7f5e7 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -48,7 +48,7 @@ class Build(models.Model): title = models.CharField( blank=False, max_length=100, - help_text='Brief description of the build') + help_text=_('Brief description of the build')) part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='builds', @@ -57,28 +57,28 @@ class Build(models.Model): 'assembly': True, 'active': True }, - help_text='Select part to build', + help_text=_('Select part to build'), ) take_from = models.ForeignKey('stock.StockLocation', on_delete=models.SET_NULL, related_name='sourcing_builds', null=True, blank=True, - help_text='Select location to take stock from for this build (leave blank to take from any stock location)' + help_text=_('Select location to take stock from for this build (leave blank to take from any stock location)') ) quantity = models.PositiveIntegerField( default=1, validators=[MinValueValidator(1)], - help_text='Number of parts to build' + help_text=_('Number of parts to build') ) status = models.PositiveIntegerField(default=BuildStatus.PENDING, choices=BuildStatus.items(), validators=[MinValueValidator(0)], - help_text='Build status') + help_text=_('Build status')) batch = models.CharField(max_length=100, blank=True, null=True, - help_text='Batch code for this build output') + help_text=_('Batch code for this build output')) creation_date = models.DateField(auto_now=True, editable=False) @@ -90,10 +90,9 @@ class Build(models.Model): related_name='builds_completed' ) - URL = InvenTreeURLField(blank=True, help_text='Link to external URL') + URL = InvenTreeURLField(blank=True, help_text=_('Link to external URL')) - notes = models.TextField(blank=True, help_text='Extra build notes') - """ Notes attached to each build output """ + notes = models.TextField(blank=True, help_text=_('Extra build notes')) @transaction.atomic def cancelBuild(self, user): @@ -399,18 +398,20 @@ class BuildItem(models.Model): Build, on_delete=models.CASCADE, related_name='allocated_stock', - help_text='Build to allocate parts' + help_text=_('Build to allocate parts') ) stock_item = models.ForeignKey( 'stock.StockItem', on_delete=models.CASCADE, related_name='allocations', - help_text='Stock Item to allocate to build', + help_text=_('Stock Item to allocate to build'), ) - quantity = models.PositiveIntegerField( + quantity = models.DecimalField( + decimal_places=5, + max_digits=15, default=1, validators=[MinValueValidator(1)], - help_text='Stock quantity to allocate to build' + help_text=_('Stock quantity to allocate to build') ) diff --git a/InvenTree/build/templates/build/allocate_edit.html b/InvenTree/build/templates/build/allocate_edit.html index d5978afa1d..ca6990ee00 100644 --- a/InvenTree/build/templates/build/allocate_edit.html +++ b/InvenTree/build/templates/build/allocate_edit.html @@ -1,12 +1,14 @@ +{% load i18n %} +{% load inventree_extras %}
-

Allocate Stock to Build

+

{% trans "Allocate Stock to Build" %}

- - + +
@@ -14,16 +16,16 @@
-

Part

+

{% trans "Part" %}

-

Available

+

{% trans "Available" %}

-

Required

+

{% trans "Required" %}

-

Allocated

+

{% trans "Allocated" %}

diff --git a/InvenTree/build/templates/build/allocate_view.html b/InvenTree/build/templates/build/allocate_view.html index f5f3952546..6100f7232e 100644 --- a/InvenTree/build/templates/build/allocate_view.html +++ b/InvenTree/build/templates/build/allocate_view.html @@ -1,22 +1,25 @@ -

Required Parts

+{% load i18n %} +{% load inventree_extras %} + +

{% trans "Required Parts" %}


- - + +
- - - - - - + + + + + + @@ -27,10 +30,10 @@ {{ item.part.full_name }} - - + + - + {% endfor %} diff --git a/InvenTree/company/migrations/0009_auto_20191118_2323.py b/InvenTree/company/migrations/0009_auto_20191118_2323.py new file mode 100644 index 0000000000..0ad6c682f2 --- /dev/null +++ b/InvenTree/company/migrations/0009_auto_20191118_2323.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:23 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0008_auto_20190913_1407'), + ] + + operations = [ + migrations.AlterField( + model_name='supplierpricebreak', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, max_digits=15, validators=[django.core.validators.MinValueValidator(1)]), + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index d1c340921a..f16902f783 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -379,7 +379,7 @@ class SupplierPriceBreak(models.Model): part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks') - quantity = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)]) + quantity = models.DecimalField(max_digits=15, decimal_places=5, default=1, validators=[MinValueValidator(1)]) cost = models.DecimalField(max_digits=10, decimal_places=5, validators=[MinValueValidator(0)]) diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 5d59143a69..cb1f0d359c 100644 --- a/InvenTree/locale/de/LC_MESSAGES/django.po +++ b/InvenTree/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-16 09:28+0000\n" +"POT-Creation-Date: 2019-11-18 23:32+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,30 +18,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:157 order/models.py:158 order/models.py:203 +#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:160 +#: InvenTree/helpers.py:178 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:181 InvenTree/helpers.py:198 +#: InvenTree/helpers.py:199 InvenTree/helpers.py:216 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:185 InvenTree/helpers.py:188 InvenTree/helpers.py:191 -#: InvenTree/helpers.py:202 +#: InvenTree/helpers.py:203 InvenTree/helpers.py:206 InvenTree/helpers.py:209 +#: InvenTree/helpers.py:220 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:208 +#: InvenTree/helpers.py:226 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:212 +#: InvenTree/helpers.py:230 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -102,7 +102,9 @@ msgstr "" msgid "Destroyed" msgstr "" -#: InvenTree/status_codes.py:83 +#: InvenTree/status_codes.py:83 build/templates/build/allocate_edit.html:28 +#: build/templates/build/allocate_view.html:21 +#: part/templates/part/part_base.html:116 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "" @@ -139,17 +141,114 @@ msgstr "" msgid "Confirm build completion" msgstr "" -#: build/models.py:381 +#: build/models.py:51 +msgid "Brief description of the build" +msgstr "" + +#: build/models.py:60 +msgid "Select part to build" +msgstr "" + +#: build/models.py:66 +msgid "" +"Select location to take stock from for this build (leave blank to take from " +"any stock location)" +msgstr "" + +#: build/models.py:72 +msgid "Number of parts to build" +msgstr "" + +#: build/models.py:78 +msgid "Build status" +msgstr "" + +#: build/models.py:81 +msgid "Batch code for this build output" +msgstr "" + +#: build/models.py:93 +msgid "Link to external URL" +msgstr "" + +#: build/models.py:95 +msgid "Extra build notes" +msgstr "" + +#: build/models.py:380 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:384 +#: build/models.py:383 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/views.py:289 stock/views.py:859 +#: build/models.py:401 +msgid "Build to allocate parts" +msgstr "" + +#: build/models.py:408 +msgid "Stock Item to allocate to build" +msgstr "" + +#: build/models.py:416 +msgid "Stock quantity to allocate to build" +msgstr "" + +#: build/templates/build/allocate_edit.html:5 +msgid "Allocate Stock to Build" +msgstr "" + +#: build/templates/build/allocate_edit.html:10 +msgid "Auto Allocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:11 +msgid "Unallocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:19 +#: build/templates/build/allocate_view.html:17 +#: order/templates/order/purchase_order_detail.html:104 +msgid "Part" +msgstr "" + +#: build/templates/build/allocate_edit.html:22 +#: build/templates/build/allocate_view.html:19 +msgid "Available" +msgstr "" + +#: build/templates/build/allocate_edit.html:25 +#: build/templates/build/allocate_view.html:20 +msgid "Required" +msgstr "" + +#: build/templates/build/allocate_view.html:4 +msgid "Required Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:9 +msgid "Allocate" +msgstr "" + +#: build/templates/build/allocate_view.html:10 +msgid "Order Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:18 +#: order/templates/order/purchase_order_detail.html:105 +#: part/templates/part/detail.html:33 +msgid "Description" +msgstr "" + +#: build/templates/build/allocate_view.html:22 +#: part/templates/part/part_base.html:122 +msgid "On Order" +msgstr "" + +#: build/views.py:289 stock/views.py:863 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "" @@ -206,63 +305,117 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/models.py:62 +#: order/models.py:63 msgid "Order reference" msgstr "" -#: order/models.py:64 +#: order/models.py:65 msgid "Order description" msgstr "" -#: order/models.py:66 +#: order/models.py:67 msgid "Link to external page" msgstr "" -#: order/models.py:83 +#: order/models.py:84 msgid "Order notes" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Company" msgstr "" -#: order/models.py:156 order/models.py:201 part/views.py:1032 -#: stock/models.py:437 +#: order/models.py:157 order/models.py:202 part/views.py:1032 +#: stock/models.py:438 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:161 +#: order/models.py:162 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:245 +#: order/models.py:246 msgid "Item quantity" msgstr "" -#: order/models.py:247 +#: order/models.py:248 msgid "Line item reference" msgstr "" -#: order/models.py:249 +#: order/models.py:250 msgid "Line item notes" msgstr "" -#: order/models.py:275 stock/templates/stock/item.html:106 +#: order/models.py:276 stock/templates/stock/item.html:107 msgid "Purchase Order" msgstr "" -#: order/models.py:284 +#: order/models.py:285 msgid "Supplier part" msgstr "" -#: order/models.py:287 +#: order/models.py:288 msgid "Number of items received" msgstr "" +#: order/templates/order/purchase_order_detail.html:60 +msgid "Purchase Order Details" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:63 +#: stock/templates/stock/item.html:125 +msgid "Supplier" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:67 +#: stock/templates/stock/item.html:146 +msgid "Status" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:71 +msgid "Created" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:76 +msgid "Issued" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:82 +#: order/templates/order/purchase_order_detail.html:110 +msgid "Received" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:103 +msgid "Line" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:106 +msgid "Order Code" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:107 +msgid "Reference" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:108 +#: stock/templates/stock/item.html:89 +#: stock/templates/stock/stock_adjust.html:20 +msgid "Quantity" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:112 +msgid "Note" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:165 +#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 +msgid "Notes" +msgstr "" + #: order/views.py:140 msgid "Confirm order cancellation" msgstr "" @@ -324,6 +477,14 @@ msgstr "" msgid "Select currency for price calculation" msgstr "" +#: part/models.py:56 +msgid "Default location for parts in this category" +msgstr "" + +#: part/models.py:59 +msgid "Default keywords for parts in this category" +msgstr "" + #: part/models.py:308 msgid "Part must be unique for name, IPN and revision" msgstr "" @@ -336,10 +497,150 @@ msgstr "" msgid "Part cannot be a variant of another part if it is already a template" msgstr "" +#: part/models.py:327 part/templates/part/detail.html:17 +msgid "Part name" +msgstr "" + +#: part/models.py:331 +msgid "Is this part a template part?" +msgstr "" + +#: part/models.py:340 +msgid "Is this part a variant of another part?" +msgstr "" + +#: part/models.py:342 +msgid "Part description" +msgstr "" + +#: part/models.py:344 +msgid "Part keywords to improve visibility in search results" +msgstr "" + +#: part/models.py:349 +msgid "Part category" +msgstr "" + +#: part/models.py:351 +msgid "Internal Part Number" +msgstr "" + +#: part/models.py:353 +msgid "Part revision or version number" +msgstr "" + +#: part/models.py:355 +msgid "Link to extenal URL" +msgstr "" + +#: part/models.py:361 +msgid "Where is this item normally stored?" +msgstr "" + +#: part/models.py:405 +msgid "Default supplier part" +msgstr "" + +#: part/models.py:408 +msgid "Minimum allowed stock level" +msgstr "" + +#: part/models.py:410 +msgid "Stock keeping units for this part" +msgstr "" + +#: part/models.py:412 +msgid "Can this part be built from other parts?" +msgstr "" + +#: part/models.py:414 +msgid "Can this part be used to build other parts?" +msgstr "" + +#: part/models.py:416 +msgid "Does this part have tracking for unique items?" +msgstr "" + +#: part/models.py:418 +msgid "Can this part be purchased from external suppliers?" +msgstr "" + +#: part/models.py:420 +msgid "Can this part be sold to customers?" +msgstr "" + +#: part/models.py:422 +msgid "Is this part active?" +msgstr "" + +#: part/models.py:424 +msgid "Is this a virtual part, such as a software product or license?" +msgstr "" + +#: part/models.py:428 +msgid "Stored BOM checksum" +msgstr "" + +#: part/models.py:935 +msgid "Select file to attach" +msgstr "" + +#: part/models.py:937 +msgid "File comment" +msgstr "" + #: part/models.py:992 msgid "Parameter template name must be unique" msgstr "" +#: part/models.py:997 +msgid "Parameter Name" +msgstr "" + +#: part/models.py:999 +msgid "Parameter Units" +msgstr "" + +#: part/models.py:1025 +msgid "Parent Part" +msgstr "" + +#: part/models.py:1027 +msgid "Parameter Template" +msgstr "" + +#: part/models.py:1029 +msgid "Parameter Value" +msgstr "" + +#: part/models.py:1053 +msgid "Select parent part" +msgstr "" + +#: part/models.py:1061 +msgid "Select part to be used in BOM" +msgstr "" + +#: part/models.py:1067 +msgid "BOM quantity for this BOM item" +msgstr "" + +#: part/models.py:1070 +msgid "Estimated build wastage quantity (absolute or percentage)" +msgstr "" + +#: part/models.py:1073 +msgid "BOM item reference" +msgstr "" + +#: part/models.py:1076 +msgid "BOM item notes" +msgstr "" + +#: part/models.py:1078 +msgid "BOM line checksum" +msgstr "" + #: part/models.py:1141 msgid "Part cannot be added to its own Bill of Materials" msgstr "" @@ -369,11 +670,11 @@ msgstr "" msgid "Category Description" msgstr "" -#: part/templates/part/category.html:46 part/templates/part/detail.html:63 +#: part/templates/part/category.html:46 part/templates/part/detail.html:64 msgid "Default Location" msgstr "" -#: part/templates/part/category.html:52 part/templates/part/detail.html:43 +#: part/templates/part/category.html:52 part/templates/part/detail.html:44 msgid "Keywords" msgstr "" @@ -385,7 +686,7 @@ msgstr "" msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:66 part/templates/part/detail.html:8 +#: part/templates/part/category.html:66 part/templates/part/detail.html:9 msgid "Part Details" msgstr "" @@ -393,116 +694,181 @@ msgstr "" msgid "Parts" msgstr "" -#: part/templates/part/detail.html:16 -msgid "Part name" -msgstr "" - -#: part/templates/part/detail.html:21 +#: part/templates/part/detail.html:22 part/templates/part/part_base.html:85 msgid "IPN" msgstr "" -#: part/templates/part/detail.html:27 +#: part/templates/part/detail.html:28 msgid "Revision" msgstr "" -#: part/templates/part/detail.html:32 -msgid "Description" -msgstr "" - -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:49 stock/templates/stock/item.html:118 +#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 +#: stock/templates/stock/item.html:119 msgid "URL" msgstr "" -#: part/templates/part/detail.html:54 +#: part/templates/part/detail.html:55 msgid "Category" msgstr "" -#: part/templates/part/detail.html:69 +#: part/templates/part/detail.html:70 msgid "Default Supplier" msgstr "" -#: part/templates/part/detail.html:76 +#: part/templates/part/detail.html:77 msgid "Units" msgstr "" -#: part/templates/part/detail.html:81 +#: part/templates/part/detail.html:82 msgid "Minimum Stock" msgstr "" -#: part/templates/part/detail.html:90 +#: part/templates/part/detail.html:91 msgid "Virtual" msgstr "" -#: part/templates/part/detail.html:93 +#: part/templates/part/detail.html:94 msgid "Part is virtual (not a physical part)" msgstr "" -#: part/templates/part/detail.html:95 +#: part/templates/part/detail.html:96 msgid "Part is not a virtual part" msgstr "" -#: part/templates/part/detail.html:99 +#: part/templates/part/detail.html:100 msgid "Assembly" msgstr "" -#: part/templates/part/detail.html:102 +#: part/templates/part/detail.html:103 msgid "Part can be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:104 +#: part/templates/part/detail.html:105 msgid "Part cannot be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:108 +#: part/templates/part/detail.html:109 msgid "Component" msgstr "" -#: part/templates/part/detail.html:111 +#: part/templates/part/detail.html:112 msgid "Part can be used in assemblies" msgstr "" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Part cannot be used in assemblies" msgstr "" -#: part/templates/part/detail.html:117 +#: part/templates/part/detail.html:118 msgid "Trackable" msgstr "" -#: part/templates/part/detail.html:120 +#: part/templates/part/detail.html:121 msgid "Part stock is tracked by serial number" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Part stock is not tracked by serial number" msgstr "" -#: part/templates/part/detail.html:126 +#: part/templates/part/detail.html:127 msgid "Purchaseable" msgstr "" -#: part/templates/part/detail.html:129 part/templates/part/detail.html:131 +#: part/templates/part/detail.html:130 part/templates/part/detail.html:132 msgid "Part can be purchased from external suppliers" msgstr "" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Sellable" msgstr "" -#: part/templates/part/detail.html:139 +#: part/templates/part/detail.html:140 msgid "Part can be sold to customers" msgstr "" -#: part/templates/part/detail.html:141 +#: part/templates/part/detail.html:142 msgid "Part cannot be sold to customers" msgstr "" -#: part/templates/part/detail.html:151 stock/templates/stock/item.html:150 -msgid "Notes" +#: part/templates/part/part_base.html:11 +msgid "This part is not active" +msgstr "" + +#: part/templates/part/part_base.html:47 +msgid "Star this part" +msgstr "" + +#: part/templates/part/part_base.html:53 +msgid "Show pricing information" +msgstr "" + +#: part/templates/part/part_base.html:105 +msgid "Available Stock" +msgstr "" + +#: part/templates/part/part_base.html:110 +msgid "In Stock" +msgstr "" + +#: part/templates/part/part_base.html:131 +msgid "Build Status" +msgstr "" + +#: part/templates/part/part_base.html:135 +msgid "Can Build" +msgstr "" + +#: part/templates/part/part_base.html:140 +msgid "Underway" +msgstr "" + +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "" + +#: part/templates/part/tabs.html:9 +msgid "Parameters" +msgstr "" + +#: part/templates/part/tabs.html:13 +msgid "Variants" +msgstr "" + +#: part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "" + +#: part/templates/part/tabs.html:26 +msgid "BOM" +msgstr "" + +#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +msgid "Build" +msgstr "" + +#: part/templates/part/tabs.html:32 +msgid "Used In" +msgstr "" + +#: part/templates/part/tabs.html:37 +msgid "Suppliers" +msgstr "" + +#: part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "" + +#: part/templates/part/tabs.html:48 +msgid "Tracking" +msgstr "" + +#: part/templates/part/tabs.html:55 +msgid "Attachments" msgstr "" #: part/views.py:196 @@ -558,141 +924,176 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:201 +#: stock/models.py:202 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" msgstr "" -#: stock/models.py:206 +#: stock/models.py:207 msgid "A stock item with this serial number already exists" msgstr "" -#: stock/models.py:225 +#: stock/models.py:226 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:235 stock/models.py:244 +#: stock/models.py:236 stock/models.py:245 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:236 +#: stock/models.py:237 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:252 +#: stock/models.py:253 msgid "Stock item cannot be created for a template Part" msgstr "" -#: stock/models.py:261 +#: stock/models.py:262 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:360 +#: stock/models.py:298 +msgid "Base part" +msgstr "" + +#: stock/models.py:305 +msgid "Select a matching supplier part for this stock item" +msgstr "" + +#: stock/models.py:309 +msgid "Where is this stock item located?" +msgstr "" + +#: stock/models.py:313 +msgid "Is this item installed in another item?" +msgstr "" + +#: stock/models.py:317 +msgid "Item assigned to customer?" +msgstr "" + +#: stock/models.py:320 +msgid "Serial number for this item" +msgstr "" + +#: stock/models.py:325 +msgid "Batch code for this stock item" +msgstr "" + +#: stock/models.py:334 +msgid "Build for this stock item" +msgstr "" + +#: stock/models.py:343 +msgid "Purchase order for this stock item" +msgstr "" + +#: stock/models.py:354 +msgid "Delete this Stock Item when stock is depleted" +msgstr "" + +#: stock/models.py:361 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:434 +#: stock/models.py:435 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:440 +#: stock/models.py:441 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:443 stock/models.py:446 +#: stock/models.py:444 stock/models.py:447 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:449 +#: stock/models.py:450 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:459 +#: stock/models.py:460 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:480 +#: stock/models.py:481 msgid "Add serial number" msgstr "" -#: stock/models.py:483 +#: stock/models.py:484 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/templates/stock/item.html:8 +#: stock/models.py:750 +msgid "Tracking entry title" +msgstr "" + +#: stock/models.py:752 +msgid "Entry notes" +msgstr "" + +#: stock/models.py:754 +msgid "Link to external page for further information" +msgstr "" + +#: stock/templates/stock/item.html:9 msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item.html:51 +#: stock/templates/stock/item.html:52 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." msgstr "" -#: stock/templates/stock/item.html:55 +#: stock/templates/stock/item.html:56 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" -#: stock/templates/stock/item.html:72 +#: stock/templates/stock/item.html:73 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item.html:77 +#: stock/templates/stock/item.html:78 #: stock/templates/stock/stock_adjust.html:16 msgid "Location" msgstr "" -#: stock/templates/stock/item.html:83 +#: stock/templates/stock/item.html:84 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item.html:88 -#: stock/templates/stock/stock_adjust.html:20 -msgid "Quantity" -msgstr "" - -#: stock/templates/stock/item.html:94 +#: stock/templates/stock/item.html:95 msgid "Batch" msgstr "" -#: stock/templates/stock/item.html:100 -msgid "Build" -msgstr "" - -#: stock/templates/stock/item.html:112 +#: stock/templates/stock/item.html:113 msgid "Customer" msgstr "" -#: stock/templates/stock/item.html:124 -msgid "Supplier" -msgstr "" - -#: stock/templates/stock/item.html:128 +#: stock/templates/stock/item.html:129 msgid "Supplier Part" msgstr "" -#: stock/templates/stock/item.html:133 +#: stock/templates/stock/item.html:134 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item.html:137 +#: stock/templates/stock/item.html:138 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item.html:141 +#: stock/templates/stock/item.html:142 msgid "No stocktake performed" msgstr "" -#: stock/templates/stock/item.html:145 -msgid "Status" -msgstr "" - -#: stock/templates/stock/item.html:159 +#: stock/templates/stock/item.html:160 msgid "Stock Tracking Information" msgstr "" @@ -729,76 +1130,140 @@ msgstr "" msgid "Stock Item" msgstr "" -#: stock/views.py:373 -msgid "Move Stock Items" +#: stock/views.py:96 +msgid "Edit Stock Location" msgstr "" -#: stock/views.py:374 -msgid "Count Stock Items" +#: stock/views.py:120 +msgid "Stock Location QR code" +msgstr "" + +#: stock/views.py:135 +msgid "Stock Export Options" +msgstr "" + +#: stock/views.py:243 +msgid "Stock Item QR Code" +msgstr "" + +#: stock/views.py:266 +msgid "Adjust Stock" msgstr "" #: stock/views.py:375 -msgid "Remove From Stock" +msgid "Move Stock Items" msgstr "" #: stock/views.py:376 -msgid "Add Stock Items" +msgid "Count Stock Items" msgstr "" #: stock/views.py:377 +msgid "Remove From Stock" +msgstr "" + +#: stock/views.py:378 +msgid "Add Stock Items" +msgstr "" + +#: stock/views.py:379 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:404 +#: stock/views.py:407 msgid "Must enter integer value" msgstr "" -#: stock/views.py:409 +#: stock/views.py:412 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:416 +#: stock/views.py:419 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:424 +#: stock/views.py:427 msgid "Confirm stock adjustment" msgstr "" -#: stock/views.py:495 +#: stock/views.py:498 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:510 +#: stock/views.py:513 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:523 +#: stock/views.py:526 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:551 +#: stock/views.py:554 msgid "No items were moved" msgstr "" -#: stock/views.py:554 +#: stock/views.py:557 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:573 +#: stock/views.py:576 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:838 +#: stock/views.py:588 +msgid "Edit Stock Item" +msgstr "" + +#: stock/views.py:624 +msgid "Create new Stock Location" +msgstr "" + +#: stock/views.py:645 +msgid "Serialize Stock" +msgstr "" + +#: stock/views.py:725 +msgid "Create new Stock Item" +msgstr "" + +#: stock/views.py:789 +msgid "Copy Stock Item" +msgstr "" + +#: stock/views.py:839 +msgid "Invalid quantity" +msgstr "" + +#: stock/views.py:842 msgid "Invalid part selection" msgstr "" -#: stock/views.py:900 +#: stock/views.py:904 msgid "Created new stock item" msgstr "" + +#: stock/views.py:921 +msgid "Delete Stock Location" +msgstr "" + +#: stock/views.py:934 +msgid "Delete Stock Item" +msgstr "" + +#: stock/views.py:945 +msgid "Delete Stock Tracking Entry" +msgstr "" + +#: stock/views.py:962 +msgid "Edit Stock Tracking Entry" +msgstr "" + +#: stock/views.py:971 +msgid "Add Stock Tracking Entry" +msgstr "" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index 5d59143a69..cb1f0d359c 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: 2019-11-16 09:28+0000\n" +"POT-Creation-Date: 2019-11-18 23:32+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,30 +18,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:157 order/models.py:158 order/models.py:203 +#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:160 +#: InvenTree/helpers.py:178 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:181 InvenTree/helpers.py:198 +#: InvenTree/helpers.py:199 InvenTree/helpers.py:216 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:185 InvenTree/helpers.py:188 InvenTree/helpers.py:191 -#: InvenTree/helpers.py:202 +#: InvenTree/helpers.py:203 InvenTree/helpers.py:206 InvenTree/helpers.py:209 +#: InvenTree/helpers.py:220 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:208 +#: InvenTree/helpers.py:226 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:212 +#: InvenTree/helpers.py:230 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -102,7 +102,9 @@ msgstr "" msgid "Destroyed" msgstr "" -#: InvenTree/status_codes.py:83 +#: InvenTree/status_codes.py:83 build/templates/build/allocate_edit.html:28 +#: build/templates/build/allocate_view.html:21 +#: part/templates/part/part_base.html:116 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "" @@ -139,17 +141,114 @@ msgstr "" msgid "Confirm build completion" msgstr "" -#: build/models.py:381 +#: build/models.py:51 +msgid "Brief description of the build" +msgstr "" + +#: build/models.py:60 +msgid "Select part to build" +msgstr "" + +#: build/models.py:66 +msgid "" +"Select location to take stock from for this build (leave blank to take from " +"any stock location)" +msgstr "" + +#: build/models.py:72 +msgid "Number of parts to build" +msgstr "" + +#: build/models.py:78 +msgid "Build status" +msgstr "" + +#: build/models.py:81 +msgid "Batch code for this build output" +msgstr "" + +#: build/models.py:93 +msgid "Link to external URL" +msgstr "" + +#: build/models.py:95 +msgid "Extra build notes" +msgstr "" + +#: build/models.py:380 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:384 +#: build/models.py:383 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/views.py:289 stock/views.py:859 +#: build/models.py:401 +msgid "Build to allocate parts" +msgstr "" + +#: build/models.py:408 +msgid "Stock Item to allocate to build" +msgstr "" + +#: build/models.py:416 +msgid "Stock quantity to allocate to build" +msgstr "" + +#: build/templates/build/allocate_edit.html:5 +msgid "Allocate Stock to Build" +msgstr "" + +#: build/templates/build/allocate_edit.html:10 +msgid "Auto Allocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:11 +msgid "Unallocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:19 +#: build/templates/build/allocate_view.html:17 +#: order/templates/order/purchase_order_detail.html:104 +msgid "Part" +msgstr "" + +#: build/templates/build/allocate_edit.html:22 +#: build/templates/build/allocate_view.html:19 +msgid "Available" +msgstr "" + +#: build/templates/build/allocate_edit.html:25 +#: build/templates/build/allocate_view.html:20 +msgid "Required" +msgstr "" + +#: build/templates/build/allocate_view.html:4 +msgid "Required Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:9 +msgid "Allocate" +msgstr "" + +#: build/templates/build/allocate_view.html:10 +msgid "Order Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:18 +#: order/templates/order/purchase_order_detail.html:105 +#: part/templates/part/detail.html:33 +msgid "Description" +msgstr "" + +#: build/templates/build/allocate_view.html:22 +#: part/templates/part/part_base.html:122 +msgid "On Order" +msgstr "" + +#: build/views.py:289 stock/views.py:863 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "" @@ -206,63 +305,117 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/models.py:62 +#: order/models.py:63 msgid "Order reference" msgstr "" -#: order/models.py:64 +#: order/models.py:65 msgid "Order description" msgstr "" -#: order/models.py:66 +#: order/models.py:67 msgid "Link to external page" msgstr "" -#: order/models.py:83 +#: order/models.py:84 msgid "Order notes" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Company" msgstr "" -#: order/models.py:156 order/models.py:201 part/views.py:1032 -#: stock/models.py:437 +#: order/models.py:157 order/models.py:202 part/views.py:1032 +#: stock/models.py:438 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:161 +#: order/models.py:162 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:245 +#: order/models.py:246 msgid "Item quantity" msgstr "" -#: order/models.py:247 +#: order/models.py:248 msgid "Line item reference" msgstr "" -#: order/models.py:249 +#: order/models.py:250 msgid "Line item notes" msgstr "" -#: order/models.py:275 stock/templates/stock/item.html:106 +#: order/models.py:276 stock/templates/stock/item.html:107 msgid "Purchase Order" msgstr "" -#: order/models.py:284 +#: order/models.py:285 msgid "Supplier part" msgstr "" -#: order/models.py:287 +#: order/models.py:288 msgid "Number of items received" msgstr "" +#: order/templates/order/purchase_order_detail.html:60 +msgid "Purchase Order Details" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:63 +#: stock/templates/stock/item.html:125 +msgid "Supplier" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:67 +#: stock/templates/stock/item.html:146 +msgid "Status" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:71 +msgid "Created" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:76 +msgid "Issued" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:82 +#: order/templates/order/purchase_order_detail.html:110 +msgid "Received" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:103 +msgid "Line" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:106 +msgid "Order Code" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:107 +msgid "Reference" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:108 +#: stock/templates/stock/item.html:89 +#: stock/templates/stock/stock_adjust.html:20 +msgid "Quantity" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:112 +msgid "Note" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:165 +#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 +msgid "Notes" +msgstr "" + #: order/views.py:140 msgid "Confirm order cancellation" msgstr "" @@ -324,6 +477,14 @@ msgstr "" msgid "Select currency for price calculation" msgstr "" +#: part/models.py:56 +msgid "Default location for parts in this category" +msgstr "" + +#: part/models.py:59 +msgid "Default keywords for parts in this category" +msgstr "" + #: part/models.py:308 msgid "Part must be unique for name, IPN and revision" msgstr "" @@ -336,10 +497,150 @@ msgstr "" msgid "Part cannot be a variant of another part if it is already a template" msgstr "" +#: part/models.py:327 part/templates/part/detail.html:17 +msgid "Part name" +msgstr "" + +#: part/models.py:331 +msgid "Is this part a template part?" +msgstr "" + +#: part/models.py:340 +msgid "Is this part a variant of another part?" +msgstr "" + +#: part/models.py:342 +msgid "Part description" +msgstr "" + +#: part/models.py:344 +msgid "Part keywords to improve visibility in search results" +msgstr "" + +#: part/models.py:349 +msgid "Part category" +msgstr "" + +#: part/models.py:351 +msgid "Internal Part Number" +msgstr "" + +#: part/models.py:353 +msgid "Part revision or version number" +msgstr "" + +#: part/models.py:355 +msgid "Link to extenal URL" +msgstr "" + +#: part/models.py:361 +msgid "Where is this item normally stored?" +msgstr "" + +#: part/models.py:405 +msgid "Default supplier part" +msgstr "" + +#: part/models.py:408 +msgid "Minimum allowed stock level" +msgstr "" + +#: part/models.py:410 +msgid "Stock keeping units for this part" +msgstr "" + +#: part/models.py:412 +msgid "Can this part be built from other parts?" +msgstr "" + +#: part/models.py:414 +msgid "Can this part be used to build other parts?" +msgstr "" + +#: part/models.py:416 +msgid "Does this part have tracking for unique items?" +msgstr "" + +#: part/models.py:418 +msgid "Can this part be purchased from external suppliers?" +msgstr "" + +#: part/models.py:420 +msgid "Can this part be sold to customers?" +msgstr "" + +#: part/models.py:422 +msgid "Is this part active?" +msgstr "" + +#: part/models.py:424 +msgid "Is this a virtual part, such as a software product or license?" +msgstr "" + +#: part/models.py:428 +msgid "Stored BOM checksum" +msgstr "" + +#: part/models.py:935 +msgid "Select file to attach" +msgstr "" + +#: part/models.py:937 +msgid "File comment" +msgstr "" + #: part/models.py:992 msgid "Parameter template name must be unique" msgstr "" +#: part/models.py:997 +msgid "Parameter Name" +msgstr "" + +#: part/models.py:999 +msgid "Parameter Units" +msgstr "" + +#: part/models.py:1025 +msgid "Parent Part" +msgstr "" + +#: part/models.py:1027 +msgid "Parameter Template" +msgstr "" + +#: part/models.py:1029 +msgid "Parameter Value" +msgstr "" + +#: part/models.py:1053 +msgid "Select parent part" +msgstr "" + +#: part/models.py:1061 +msgid "Select part to be used in BOM" +msgstr "" + +#: part/models.py:1067 +msgid "BOM quantity for this BOM item" +msgstr "" + +#: part/models.py:1070 +msgid "Estimated build wastage quantity (absolute or percentage)" +msgstr "" + +#: part/models.py:1073 +msgid "BOM item reference" +msgstr "" + +#: part/models.py:1076 +msgid "BOM item notes" +msgstr "" + +#: part/models.py:1078 +msgid "BOM line checksum" +msgstr "" + #: part/models.py:1141 msgid "Part cannot be added to its own Bill of Materials" msgstr "" @@ -369,11 +670,11 @@ msgstr "" msgid "Category Description" msgstr "" -#: part/templates/part/category.html:46 part/templates/part/detail.html:63 +#: part/templates/part/category.html:46 part/templates/part/detail.html:64 msgid "Default Location" msgstr "" -#: part/templates/part/category.html:52 part/templates/part/detail.html:43 +#: part/templates/part/category.html:52 part/templates/part/detail.html:44 msgid "Keywords" msgstr "" @@ -385,7 +686,7 @@ msgstr "" msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:66 part/templates/part/detail.html:8 +#: part/templates/part/category.html:66 part/templates/part/detail.html:9 msgid "Part Details" msgstr "" @@ -393,116 +694,181 @@ msgstr "" msgid "Parts" msgstr "" -#: part/templates/part/detail.html:16 -msgid "Part name" -msgstr "" - -#: part/templates/part/detail.html:21 +#: part/templates/part/detail.html:22 part/templates/part/part_base.html:85 msgid "IPN" msgstr "" -#: part/templates/part/detail.html:27 +#: part/templates/part/detail.html:28 msgid "Revision" msgstr "" -#: part/templates/part/detail.html:32 -msgid "Description" -msgstr "" - -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:49 stock/templates/stock/item.html:118 +#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 +#: stock/templates/stock/item.html:119 msgid "URL" msgstr "" -#: part/templates/part/detail.html:54 +#: part/templates/part/detail.html:55 msgid "Category" msgstr "" -#: part/templates/part/detail.html:69 +#: part/templates/part/detail.html:70 msgid "Default Supplier" msgstr "" -#: part/templates/part/detail.html:76 +#: part/templates/part/detail.html:77 msgid "Units" msgstr "" -#: part/templates/part/detail.html:81 +#: part/templates/part/detail.html:82 msgid "Minimum Stock" msgstr "" -#: part/templates/part/detail.html:90 +#: part/templates/part/detail.html:91 msgid "Virtual" msgstr "" -#: part/templates/part/detail.html:93 +#: part/templates/part/detail.html:94 msgid "Part is virtual (not a physical part)" msgstr "" -#: part/templates/part/detail.html:95 +#: part/templates/part/detail.html:96 msgid "Part is not a virtual part" msgstr "" -#: part/templates/part/detail.html:99 +#: part/templates/part/detail.html:100 msgid "Assembly" msgstr "" -#: part/templates/part/detail.html:102 +#: part/templates/part/detail.html:103 msgid "Part can be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:104 +#: part/templates/part/detail.html:105 msgid "Part cannot be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:108 +#: part/templates/part/detail.html:109 msgid "Component" msgstr "" -#: part/templates/part/detail.html:111 +#: part/templates/part/detail.html:112 msgid "Part can be used in assemblies" msgstr "" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Part cannot be used in assemblies" msgstr "" -#: part/templates/part/detail.html:117 +#: part/templates/part/detail.html:118 msgid "Trackable" msgstr "" -#: part/templates/part/detail.html:120 +#: part/templates/part/detail.html:121 msgid "Part stock is tracked by serial number" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Part stock is not tracked by serial number" msgstr "" -#: part/templates/part/detail.html:126 +#: part/templates/part/detail.html:127 msgid "Purchaseable" msgstr "" -#: part/templates/part/detail.html:129 part/templates/part/detail.html:131 +#: part/templates/part/detail.html:130 part/templates/part/detail.html:132 msgid "Part can be purchased from external suppliers" msgstr "" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Sellable" msgstr "" -#: part/templates/part/detail.html:139 +#: part/templates/part/detail.html:140 msgid "Part can be sold to customers" msgstr "" -#: part/templates/part/detail.html:141 +#: part/templates/part/detail.html:142 msgid "Part cannot be sold to customers" msgstr "" -#: part/templates/part/detail.html:151 stock/templates/stock/item.html:150 -msgid "Notes" +#: part/templates/part/part_base.html:11 +msgid "This part is not active" +msgstr "" + +#: part/templates/part/part_base.html:47 +msgid "Star this part" +msgstr "" + +#: part/templates/part/part_base.html:53 +msgid "Show pricing information" +msgstr "" + +#: part/templates/part/part_base.html:105 +msgid "Available Stock" +msgstr "" + +#: part/templates/part/part_base.html:110 +msgid "In Stock" +msgstr "" + +#: part/templates/part/part_base.html:131 +msgid "Build Status" +msgstr "" + +#: part/templates/part/part_base.html:135 +msgid "Can Build" +msgstr "" + +#: part/templates/part/part_base.html:140 +msgid "Underway" +msgstr "" + +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "" + +#: part/templates/part/tabs.html:9 +msgid "Parameters" +msgstr "" + +#: part/templates/part/tabs.html:13 +msgid "Variants" +msgstr "" + +#: part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "" + +#: part/templates/part/tabs.html:26 +msgid "BOM" +msgstr "" + +#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +msgid "Build" +msgstr "" + +#: part/templates/part/tabs.html:32 +msgid "Used In" +msgstr "" + +#: part/templates/part/tabs.html:37 +msgid "Suppliers" +msgstr "" + +#: part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "" + +#: part/templates/part/tabs.html:48 +msgid "Tracking" +msgstr "" + +#: part/templates/part/tabs.html:55 +msgid "Attachments" msgstr "" #: part/views.py:196 @@ -558,141 +924,176 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:201 +#: stock/models.py:202 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" msgstr "" -#: stock/models.py:206 +#: stock/models.py:207 msgid "A stock item with this serial number already exists" msgstr "" -#: stock/models.py:225 +#: stock/models.py:226 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:235 stock/models.py:244 +#: stock/models.py:236 stock/models.py:245 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:236 +#: stock/models.py:237 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:252 +#: stock/models.py:253 msgid "Stock item cannot be created for a template Part" msgstr "" -#: stock/models.py:261 +#: stock/models.py:262 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:360 +#: stock/models.py:298 +msgid "Base part" +msgstr "" + +#: stock/models.py:305 +msgid "Select a matching supplier part for this stock item" +msgstr "" + +#: stock/models.py:309 +msgid "Where is this stock item located?" +msgstr "" + +#: stock/models.py:313 +msgid "Is this item installed in another item?" +msgstr "" + +#: stock/models.py:317 +msgid "Item assigned to customer?" +msgstr "" + +#: stock/models.py:320 +msgid "Serial number for this item" +msgstr "" + +#: stock/models.py:325 +msgid "Batch code for this stock item" +msgstr "" + +#: stock/models.py:334 +msgid "Build for this stock item" +msgstr "" + +#: stock/models.py:343 +msgid "Purchase order for this stock item" +msgstr "" + +#: stock/models.py:354 +msgid "Delete this Stock Item when stock is depleted" +msgstr "" + +#: stock/models.py:361 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:434 +#: stock/models.py:435 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:440 +#: stock/models.py:441 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:443 stock/models.py:446 +#: stock/models.py:444 stock/models.py:447 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:449 +#: stock/models.py:450 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:459 +#: stock/models.py:460 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:480 +#: stock/models.py:481 msgid "Add serial number" msgstr "" -#: stock/models.py:483 +#: stock/models.py:484 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/templates/stock/item.html:8 +#: stock/models.py:750 +msgid "Tracking entry title" +msgstr "" + +#: stock/models.py:752 +msgid "Entry notes" +msgstr "" + +#: stock/models.py:754 +msgid "Link to external page for further information" +msgstr "" + +#: stock/templates/stock/item.html:9 msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item.html:51 +#: stock/templates/stock/item.html:52 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." msgstr "" -#: stock/templates/stock/item.html:55 +#: stock/templates/stock/item.html:56 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" -#: stock/templates/stock/item.html:72 +#: stock/templates/stock/item.html:73 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item.html:77 +#: stock/templates/stock/item.html:78 #: stock/templates/stock/stock_adjust.html:16 msgid "Location" msgstr "" -#: stock/templates/stock/item.html:83 +#: stock/templates/stock/item.html:84 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item.html:88 -#: stock/templates/stock/stock_adjust.html:20 -msgid "Quantity" -msgstr "" - -#: stock/templates/stock/item.html:94 +#: stock/templates/stock/item.html:95 msgid "Batch" msgstr "" -#: stock/templates/stock/item.html:100 -msgid "Build" -msgstr "" - -#: stock/templates/stock/item.html:112 +#: stock/templates/stock/item.html:113 msgid "Customer" msgstr "" -#: stock/templates/stock/item.html:124 -msgid "Supplier" -msgstr "" - -#: stock/templates/stock/item.html:128 +#: stock/templates/stock/item.html:129 msgid "Supplier Part" msgstr "" -#: stock/templates/stock/item.html:133 +#: stock/templates/stock/item.html:134 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item.html:137 +#: stock/templates/stock/item.html:138 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item.html:141 +#: stock/templates/stock/item.html:142 msgid "No stocktake performed" msgstr "" -#: stock/templates/stock/item.html:145 -msgid "Status" -msgstr "" - -#: stock/templates/stock/item.html:159 +#: stock/templates/stock/item.html:160 msgid "Stock Tracking Information" msgstr "" @@ -729,76 +1130,140 @@ msgstr "" msgid "Stock Item" msgstr "" -#: stock/views.py:373 -msgid "Move Stock Items" +#: stock/views.py:96 +msgid "Edit Stock Location" msgstr "" -#: stock/views.py:374 -msgid "Count Stock Items" +#: stock/views.py:120 +msgid "Stock Location QR code" +msgstr "" + +#: stock/views.py:135 +msgid "Stock Export Options" +msgstr "" + +#: stock/views.py:243 +msgid "Stock Item QR Code" +msgstr "" + +#: stock/views.py:266 +msgid "Adjust Stock" msgstr "" #: stock/views.py:375 -msgid "Remove From Stock" +msgid "Move Stock Items" msgstr "" #: stock/views.py:376 -msgid "Add Stock Items" +msgid "Count Stock Items" msgstr "" #: stock/views.py:377 +msgid "Remove From Stock" +msgstr "" + +#: stock/views.py:378 +msgid "Add Stock Items" +msgstr "" + +#: stock/views.py:379 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:404 +#: stock/views.py:407 msgid "Must enter integer value" msgstr "" -#: stock/views.py:409 +#: stock/views.py:412 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:416 +#: stock/views.py:419 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:424 +#: stock/views.py:427 msgid "Confirm stock adjustment" msgstr "" -#: stock/views.py:495 +#: stock/views.py:498 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:510 +#: stock/views.py:513 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:523 +#: stock/views.py:526 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:551 +#: stock/views.py:554 msgid "No items were moved" msgstr "" -#: stock/views.py:554 +#: stock/views.py:557 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:573 +#: stock/views.py:576 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:838 +#: stock/views.py:588 +msgid "Edit Stock Item" +msgstr "" + +#: stock/views.py:624 +msgid "Create new Stock Location" +msgstr "" + +#: stock/views.py:645 +msgid "Serialize Stock" +msgstr "" + +#: stock/views.py:725 +msgid "Create new Stock Item" +msgstr "" + +#: stock/views.py:789 +msgid "Copy Stock Item" +msgstr "" + +#: stock/views.py:839 +msgid "Invalid quantity" +msgstr "" + +#: stock/views.py:842 msgid "Invalid part selection" msgstr "" -#: stock/views.py:900 +#: stock/views.py:904 msgid "Created new stock item" msgstr "" + +#: stock/views.py:921 +msgid "Delete Stock Location" +msgstr "" + +#: stock/views.py:934 +msgid "Delete Stock Item" +msgstr "" + +#: stock/views.py:945 +msgid "Delete Stock Tracking Entry" +msgstr "" + +#: stock/views.py:962 +msgid "Edit Stock Tracking Entry" +msgstr "" + +#: stock/views.py:971 +msgid "Add Stock Tracking Entry" +msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index 5d59143a69..cb1f0d359c 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: 2019-11-16 09:28+0000\n" +"POT-Creation-Date: 2019-11-18 23:32+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,30 +18,30 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:157 order/models.py:158 order/models.py:203 +#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204 msgid "Invalid quantity provided" msgstr "" -#: InvenTree/helpers.py:160 +#: InvenTree/helpers.py:178 msgid "Empty serial number string" msgstr "" -#: InvenTree/helpers.py:181 InvenTree/helpers.py:198 +#: InvenTree/helpers.py:199 InvenTree/helpers.py:216 #, python-brace-format msgid "Duplicate serial: {n}" msgstr "" -#: InvenTree/helpers.py:185 InvenTree/helpers.py:188 InvenTree/helpers.py:191 -#: InvenTree/helpers.py:202 +#: InvenTree/helpers.py:203 InvenTree/helpers.py:206 InvenTree/helpers.py:209 +#: InvenTree/helpers.py:220 #, python-brace-format msgid "Invalid group: {g}" msgstr "" -#: InvenTree/helpers.py:208 +#: InvenTree/helpers.py:226 msgid "No serial numbers found" msgstr "" -#: InvenTree/helpers.py:212 +#: InvenTree/helpers.py:230 #, python-brace-format msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" @@ -102,7 +102,9 @@ msgstr "" msgid "Destroyed" msgstr "" -#: InvenTree/status_codes.py:83 +#: InvenTree/status_codes.py:83 build/templates/build/allocate_edit.html:28 +#: build/templates/build/allocate_view.html:21 +#: part/templates/part/part_base.html:116 part/templates/part/tabs.html:21 msgid "Allocated" msgstr "" @@ -139,17 +141,114 @@ msgstr "" msgid "Confirm build completion" msgstr "" -#: build/models.py:381 +#: build/models.py:51 +msgid "Brief description of the build" +msgstr "" + +#: build/models.py:60 +msgid "Select part to build" +msgstr "" + +#: build/models.py:66 +msgid "" +"Select location to take stock from for this build (leave blank to take from " +"any stock location)" +msgstr "" + +#: build/models.py:72 +msgid "Number of parts to build" +msgstr "" + +#: build/models.py:78 +msgid "Build status" +msgstr "" + +#: build/models.py:81 +msgid "Batch code for this build output" +msgstr "" + +#: build/models.py:93 +msgid "Link to external URL" +msgstr "" + +#: build/models.py:95 +msgid "Extra build notes" +msgstr "" + +#: build/models.py:380 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:384 +#: build/models.py:383 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/views.py:289 stock/views.py:859 +#: build/models.py:401 +msgid "Build to allocate parts" +msgstr "" + +#: build/models.py:408 +msgid "Stock Item to allocate to build" +msgstr "" + +#: build/models.py:416 +msgid "Stock quantity to allocate to build" +msgstr "" + +#: build/templates/build/allocate_edit.html:5 +msgid "Allocate Stock to Build" +msgstr "" + +#: build/templates/build/allocate_edit.html:10 +msgid "Auto Allocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:11 +msgid "Unallocate" +msgstr "" + +#: build/templates/build/allocate_edit.html:19 +#: build/templates/build/allocate_view.html:17 +#: order/templates/order/purchase_order_detail.html:104 +msgid "Part" +msgstr "" + +#: build/templates/build/allocate_edit.html:22 +#: build/templates/build/allocate_view.html:19 +msgid "Available" +msgstr "" + +#: build/templates/build/allocate_edit.html:25 +#: build/templates/build/allocate_view.html:20 +msgid "Required" +msgstr "" + +#: build/templates/build/allocate_view.html:4 +msgid "Required Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:9 +msgid "Allocate" +msgstr "" + +#: build/templates/build/allocate_view.html:10 +msgid "Order Parts" +msgstr "" + +#: build/templates/build/allocate_view.html:18 +#: order/templates/order/purchase_order_detail.html:105 +#: part/templates/part/detail.html:33 +msgid "Description" +msgstr "" + +#: build/templates/build/allocate_view.html:22 +#: part/templates/part/part_base.html:122 +msgid "On Order" +msgstr "" + +#: build/views.py:289 stock/views.py:863 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "" @@ -206,63 +305,117 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/models.py:62 +#: order/models.py:63 msgid "Order reference" msgstr "" -#: order/models.py:64 +#: order/models.py:65 msgid "Order description" msgstr "" -#: order/models.py:66 +#: order/models.py:67 msgid "Link to external page" msgstr "" -#: order/models.py:83 +#: order/models.py:84 msgid "Order notes" msgstr "" -#: order/models.py:125 +#: order/models.py:126 msgid "Company" msgstr "" -#: order/models.py:156 order/models.py:201 part/views.py:1032 -#: stock/models.py:437 +#: order/models.py:157 order/models.py:202 part/views.py:1032 +#: stock/models.py:438 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:161 +#: order/models.py:162 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:196 +#: order/models.py:197 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:245 +#: order/models.py:246 msgid "Item quantity" msgstr "" -#: order/models.py:247 +#: order/models.py:248 msgid "Line item reference" msgstr "" -#: order/models.py:249 +#: order/models.py:250 msgid "Line item notes" msgstr "" -#: order/models.py:275 stock/templates/stock/item.html:106 +#: order/models.py:276 stock/templates/stock/item.html:107 msgid "Purchase Order" msgstr "" -#: order/models.py:284 +#: order/models.py:285 msgid "Supplier part" msgstr "" -#: order/models.py:287 +#: order/models.py:288 msgid "Number of items received" msgstr "" +#: order/templates/order/purchase_order_detail.html:60 +msgid "Purchase Order Details" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:63 +#: stock/templates/stock/item.html:125 +msgid "Supplier" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:67 +#: stock/templates/stock/item.html:146 +msgid "Status" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:71 +msgid "Created" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:76 +msgid "Issued" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:82 +#: order/templates/order/purchase_order_detail.html:110 +msgid "Received" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:103 +msgid "Line" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:106 +msgid "Order Code" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:107 +msgid "Reference" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:108 +#: stock/templates/stock/item.html:89 +#: stock/templates/stock/stock_adjust.html:20 +msgid "Quantity" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:112 +msgid "Note" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:165 +#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 +msgid "Notes" +msgstr "" + #: order/views.py:140 msgid "Confirm order cancellation" msgstr "" @@ -324,6 +477,14 @@ msgstr "" msgid "Select currency for price calculation" msgstr "" +#: part/models.py:56 +msgid "Default location for parts in this category" +msgstr "" + +#: part/models.py:59 +msgid "Default keywords for parts in this category" +msgstr "" + #: part/models.py:308 msgid "Part must be unique for name, IPN and revision" msgstr "" @@ -336,10 +497,150 @@ msgstr "" msgid "Part cannot be a variant of another part if it is already a template" msgstr "" +#: part/models.py:327 part/templates/part/detail.html:17 +msgid "Part name" +msgstr "" + +#: part/models.py:331 +msgid "Is this part a template part?" +msgstr "" + +#: part/models.py:340 +msgid "Is this part a variant of another part?" +msgstr "" + +#: part/models.py:342 +msgid "Part description" +msgstr "" + +#: part/models.py:344 +msgid "Part keywords to improve visibility in search results" +msgstr "" + +#: part/models.py:349 +msgid "Part category" +msgstr "" + +#: part/models.py:351 +msgid "Internal Part Number" +msgstr "" + +#: part/models.py:353 +msgid "Part revision or version number" +msgstr "" + +#: part/models.py:355 +msgid "Link to extenal URL" +msgstr "" + +#: part/models.py:361 +msgid "Where is this item normally stored?" +msgstr "" + +#: part/models.py:405 +msgid "Default supplier part" +msgstr "" + +#: part/models.py:408 +msgid "Minimum allowed stock level" +msgstr "" + +#: part/models.py:410 +msgid "Stock keeping units for this part" +msgstr "" + +#: part/models.py:412 +msgid "Can this part be built from other parts?" +msgstr "" + +#: part/models.py:414 +msgid "Can this part be used to build other parts?" +msgstr "" + +#: part/models.py:416 +msgid "Does this part have tracking for unique items?" +msgstr "" + +#: part/models.py:418 +msgid "Can this part be purchased from external suppliers?" +msgstr "" + +#: part/models.py:420 +msgid "Can this part be sold to customers?" +msgstr "" + +#: part/models.py:422 +msgid "Is this part active?" +msgstr "" + +#: part/models.py:424 +msgid "Is this a virtual part, such as a software product or license?" +msgstr "" + +#: part/models.py:428 +msgid "Stored BOM checksum" +msgstr "" + +#: part/models.py:935 +msgid "Select file to attach" +msgstr "" + +#: part/models.py:937 +msgid "File comment" +msgstr "" + #: part/models.py:992 msgid "Parameter template name must be unique" msgstr "" +#: part/models.py:997 +msgid "Parameter Name" +msgstr "" + +#: part/models.py:999 +msgid "Parameter Units" +msgstr "" + +#: part/models.py:1025 +msgid "Parent Part" +msgstr "" + +#: part/models.py:1027 +msgid "Parameter Template" +msgstr "" + +#: part/models.py:1029 +msgid "Parameter Value" +msgstr "" + +#: part/models.py:1053 +msgid "Select parent part" +msgstr "" + +#: part/models.py:1061 +msgid "Select part to be used in BOM" +msgstr "" + +#: part/models.py:1067 +msgid "BOM quantity for this BOM item" +msgstr "" + +#: part/models.py:1070 +msgid "Estimated build wastage quantity (absolute or percentage)" +msgstr "" + +#: part/models.py:1073 +msgid "BOM item reference" +msgstr "" + +#: part/models.py:1076 +msgid "BOM item notes" +msgstr "" + +#: part/models.py:1078 +msgid "BOM line checksum" +msgstr "" + #: part/models.py:1141 msgid "Part cannot be added to its own Bill of Materials" msgstr "" @@ -369,11 +670,11 @@ msgstr "" msgid "Category Description" msgstr "" -#: part/templates/part/category.html:46 part/templates/part/detail.html:63 +#: part/templates/part/category.html:46 part/templates/part/detail.html:64 msgid "Default Location" msgstr "" -#: part/templates/part/category.html:52 part/templates/part/detail.html:43 +#: part/templates/part/category.html:52 part/templates/part/detail.html:44 msgid "Keywords" msgstr "" @@ -385,7 +686,7 @@ msgstr "" msgid "Parts (Including subcategories)" msgstr "" -#: part/templates/part/category.html:66 part/templates/part/detail.html:8 +#: part/templates/part/category.html:66 part/templates/part/detail.html:9 msgid "Part Details" msgstr "" @@ -393,116 +694,181 @@ msgstr "" msgid "Parts" msgstr "" -#: part/templates/part/detail.html:16 -msgid "Part name" -msgstr "" - -#: part/templates/part/detail.html:21 +#: part/templates/part/detail.html:22 part/templates/part/part_base.html:85 msgid "IPN" msgstr "" -#: part/templates/part/detail.html:27 +#: part/templates/part/detail.html:28 msgid "Revision" msgstr "" -#: part/templates/part/detail.html:32 -msgid "Description" -msgstr "" - -#: part/templates/part/detail.html:37 +#: part/templates/part/detail.html:38 msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:49 stock/templates/stock/item.html:118 +#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 +#: stock/templates/stock/item.html:119 msgid "URL" msgstr "" -#: part/templates/part/detail.html:54 +#: part/templates/part/detail.html:55 msgid "Category" msgstr "" -#: part/templates/part/detail.html:69 +#: part/templates/part/detail.html:70 msgid "Default Supplier" msgstr "" -#: part/templates/part/detail.html:76 +#: part/templates/part/detail.html:77 msgid "Units" msgstr "" -#: part/templates/part/detail.html:81 +#: part/templates/part/detail.html:82 msgid "Minimum Stock" msgstr "" -#: part/templates/part/detail.html:90 +#: part/templates/part/detail.html:91 msgid "Virtual" msgstr "" -#: part/templates/part/detail.html:93 +#: part/templates/part/detail.html:94 msgid "Part is virtual (not a physical part)" msgstr "" -#: part/templates/part/detail.html:95 +#: part/templates/part/detail.html:96 msgid "Part is not a virtual part" msgstr "" -#: part/templates/part/detail.html:99 +#: part/templates/part/detail.html:100 msgid "Assembly" msgstr "" -#: part/templates/part/detail.html:102 +#: part/templates/part/detail.html:103 msgid "Part can be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:104 +#: part/templates/part/detail.html:105 msgid "Part cannot be assembled from other parts" msgstr "" -#: part/templates/part/detail.html:108 +#: part/templates/part/detail.html:109 msgid "Component" msgstr "" -#: part/templates/part/detail.html:111 +#: part/templates/part/detail.html:112 msgid "Part can be used in assemblies" msgstr "" -#: part/templates/part/detail.html:113 +#: part/templates/part/detail.html:114 msgid "Part cannot be used in assemblies" msgstr "" -#: part/templates/part/detail.html:117 +#: part/templates/part/detail.html:118 msgid "Trackable" msgstr "" -#: part/templates/part/detail.html:120 +#: part/templates/part/detail.html:121 msgid "Part stock is tracked by serial number" msgstr "" -#: part/templates/part/detail.html:122 +#: part/templates/part/detail.html:123 msgid "Part stock is not tracked by serial number" msgstr "" -#: part/templates/part/detail.html:126 +#: part/templates/part/detail.html:127 msgid "Purchaseable" msgstr "" -#: part/templates/part/detail.html:129 part/templates/part/detail.html:131 +#: part/templates/part/detail.html:130 part/templates/part/detail.html:132 msgid "Part can be purchased from external suppliers" msgstr "" -#: part/templates/part/detail.html:136 +#: part/templates/part/detail.html:137 msgid "Sellable" msgstr "" -#: part/templates/part/detail.html:139 +#: part/templates/part/detail.html:140 msgid "Part can be sold to customers" msgstr "" -#: part/templates/part/detail.html:141 +#: part/templates/part/detail.html:142 msgid "Part cannot be sold to customers" msgstr "" -#: part/templates/part/detail.html:151 stock/templates/stock/item.html:150 -msgid "Notes" +#: part/templates/part/part_base.html:11 +msgid "This part is not active" +msgstr "" + +#: part/templates/part/part_base.html:47 +msgid "Star this part" +msgstr "" + +#: part/templates/part/part_base.html:53 +msgid "Show pricing information" +msgstr "" + +#: part/templates/part/part_base.html:105 +msgid "Available Stock" +msgstr "" + +#: part/templates/part/part_base.html:110 +msgid "In Stock" +msgstr "" + +#: part/templates/part/part_base.html:131 +msgid "Build Status" +msgstr "" + +#: part/templates/part/part_base.html:135 +msgid "Can Build" +msgstr "" + +#: part/templates/part/part_base.html:140 +msgid "Underway" +msgstr "" + +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "" + +#: part/templates/part/tabs.html:9 +msgid "Parameters" +msgstr "" + +#: part/templates/part/tabs.html:13 +msgid "Variants" +msgstr "" + +#: part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "" + +#: part/templates/part/tabs.html:26 +msgid "BOM" +msgstr "" + +#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +msgid "Build" +msgstr "" + +#: part/templates/part/tabs.html:32 +msgid "Used In" +msgstr "" + +#: part/templates/part/tabs.html:37 +msgid "Suppliers" +msgstr "" + +#: part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "" + +#: part/templates/part/tabs.html:48 +msgid "Tracking" +msgstr "" + +#: part/templates/part/tabs.html:55 +msgid "Attachments" msgstr "" #: part/views.py:196 @@ -558,141 +924,176 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:201 +#: stock/models.py:202 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" msgstr "" -#: stock/models.py:206 +#: stock/models.py:207 msgid "A stock item with this serial number already exists" msgstr "" -#: stock/models.py:225 +#: stock/models.py:226 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:235 stock/models.py:244 +#: stock/models.py:236 stock/models.py:245 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:236 +#: stock/models.py:237 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:252 +#: stock/models.py:253 msgid "Stock item cannot be created for a template Part" msgstr "" -#: stock/models.py:261 +#: stock/models.py:262 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:360 +#: stock/models.py:298 +msgid "Base part" +msgstr "" + +#: stock/models.py:305 +msgid "Select a matching supplier part for this stock item" +msgstr "" + +#: stock/models.py:309 +msgid "Where is this stock item located?" +msgstr "" + +#: stock/models.py:313 +msgid "Is this item installed in another item?" +msgstr "" + +#: stock/models.py:317 +msgid "Item assigned to customer?" +msgstr "" + +#: stock/models.py:320 +msgid "Serial number for this item" +msgstr "" + +#: stock/models.py:325 +msgid "Batch code for this stock item" +msgstr "" + +#: stock/models.py:334 +msgid "Build for this stock item" +msgstr "" + +#: stock/models.py:343 +msgid "Purchase order for this stock item" +msgstr "" + +#: stock/models.py:354 +msgid "Delete this Stock Item when stock is depleted" +msgstr "" + +#: stock/models.py:361 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:434 +#: stock/models.py:435 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:440 +#: stock/models.py:441 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:443 stock/models.py:446 +#: stock/models.py:444 stock/models.py:447 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:449 +#: stock/models.py:450 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:459 +#: stock/models.py:460 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:480 +#: stock/models.py:481 msgid "Add serial number" msgstr "" -#: stock/models.py:483 +#: stock/models.py:484 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/templates/stock/item.html:8 +#: stock/models.py:750 +msgid "Tracking entry title" +msgstr "" + +#: stock/models.py:752 +msgid "Entry notes" +msgstr "" + +#: stock/models.py:754 +msgid "Link to external page for further information" +msgstr "" + +#: stock/templates/stock/item.html:9 msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item.html:51 +#: stock/templates/stock/item.html:52 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." msgstr "" -#: stock/templates/stock/item.html:55 +#: stock/templates/stock/item.html:56 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" -#: stock/templates/stock/item.html:72 +#: stock/templates/stock/item.html:73 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item.html:77 +#: stock/templates/stock/item.html:78 #: stock/templates/stock/stock_adjust.html:16 msgid "Location" msgstr "" -#: stock/templates/stock/item.html:83 +#: stock/templates/stock/item.html:84 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item.html:88 -#: stock/templates/stock/stock_adjust.html:20 -msgid "Quantity" -msgstr "" - -#: stock/templates/stock/item.html:94 +#: stock/templates/stock/item.html:95 msgid "Batch" msgstr "" -#: stock/templates/stock/item.html:100 -msgid "Build" -msgstr "" - -#: stock/templates/stock/item.html:112 +#: stock/templates/stock/item.html:113 msgid "Customer" msgstr "" -#: stock/templates/stock/item.html:124 -msgid "Supplier" -msgstr "" - -#: stock/templates/stock/item.html:128 +#: stock/templates/stock/item.html:129 msgid "Supplier Part" msgstr "" -#: stock/templates/stock/item.html:133 +#: stock/templates/stock/item.html:134 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item.html:137 +#: stock/templates/stock/item.html:138 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item.html:141 +#: stock/templates/stock/item.html:142 msgid "No stocktake performed" msgstr "" -#: stock/templates/stock/item.html:145 -msgid "Status" -msgstr "" - -#: stock/templates/stock/item.html:159 +#: stock/templates/stock/item.html:160 msgid "Stock Tracking Information" msgstr "" @@ -729,76 +1130,140 @@ msgstr "" msgid "Stock Item" msgstr "" -#: stock/views.py:373 -msgid "Move Stock Items" +#: stock/views.py:96 +msgid "Edit Stock Location" msgstr "" -#: stock/views.py:374 -msgid "Count Stock Items" +#: stock/views.py:120 +msgid "Stock Location QR code" +msgstr "" + +#: stock/views.py:135 +msgid "Stock Export Options" +msgstr "" + +#: stock/views.py:243 +msgid "Stock Item QR Code" +msgstr "" + +#: stock/views.py:266 +msgid "Adjust Stock" msgstr "" #: stock/views.py:375 -msgid "Remove From Stock" +msgid "Move Stock Items" msgstr "" #: stock/views.py:376 -msgid "Add Stock Items" +msgid "Count Stock Items" msgstr "" #: stock/views.py:377 +msgid "Remove From Stock" +msgstr "" + +#: stock/views.py:378 +msgid "Add Stock Items" +msgstr "" + +#: stock/views.py:379 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:404 +#: stock/views.py:407 msgid "Must enter integer value" msgstr "" -#: stock/views.py:409 +#: stock/views.py:412 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:416 +#: stock/views.py:419 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:424 +#: stock/views.py:427 msgid "Confirm stock adjustment" msgstr "" -#: stock/views.py:495 +#: stock/views.py:498 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:510 +#: stock/views.py:513 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:523 +#: stock/views.py:526 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:551 +#: stock/views.py:554 msgid "No items were moved" msgstr "" -#: stock/views.py:554 +#: stock/views.py:557 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:573 +#: stock/views.py:576 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:838 +#: stock/views.py:588 +msgid "Edit Stock Item" +msgstr "" + +#: stock/views.py:624 +msgid "Create new Stock Location" +msgstr "" + +#: stock/views.py:645 +msgid "Serialize Stock" +msgstr "" + +#: stock/views.py:725 +msgid "Create new Stock Item" +msgstr "" + +#: stock/views.py:789 +msgid "Copy Stock Item" +msgstr "" + +#: stock/views.py:839 +msgid "Invalid quantity" +msgstr "" + +#: stock/views.py:842 msgid "Invalid part selection" msgstr "" -#: stock/views.py:900 +#: stock/views.py:904 msgid "Created new stock item" msgstr "" + +#: stock/views.py:921 +msgid "Delete Stock Location" +msgstr "" + +#: stock/views.py:934 +msgid "Delete Stock Item" +msgstr "" + +#: stock/views.py:945 +msgid "Delete Stock Tracking Entry" +msgstr "" + +#: stock/views.py:962 +msgid "Edit Stock Tracking Entry" +msgstr "" + +#: stock/views.py:971 +msgid "Add Stock Tracking Entry" +msgstr "" diff --git a/InvenTree/order/migrations/0013_auto_20191118_2323.py b/InvenTree/order/migrations/0013_auto_20191118_2323.py new file mode 100644 index 0000000000..33db8f9ebd --- /dev/null +++ b/InvenTree/order/migrations/0013_auto_20191118_2323.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:23 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0012_auto_20190617_1943'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorderlineitem', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, help_text='Item quantity', max_digits=15, validators=[django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/InvenTree/order/migrations/0014_auto_20191118_2328.py b/InvenTree/order/migrations/0014_auto_20191118_2328.py new file mode 100644 index 0000000000..6020fddd87 --- /dev/null +++ b/InvenTree/order/migrations/0014_auto_20191118_2328.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0013_auto_20191118_2323'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorderlineitem', + name='received', + field=models.DecimalField(decimal_places=5, default=0, help_text='Number of items received', max_digits=15), + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index de0ac86bad..b1b93b990a 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -17,6 +17,7 @@ from datetime import datetime from stock.models import StockItem from company.models import Company, SupplierPart +from InvenTree.helpers import decimal2string from InvenTree.status_codes import OrderStatus @@ -242,7 +243,7 @@ class OrderLineItem(models.Model): class Meta: abstract = True - quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1, help_text=_('Item quantity')) + quantity = models.DecimalField(max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], default=1, help_text=_('Item quantity')) reference = models.CharField(max_length=100, blank=True, help_text=_('Line item reference')) @@ -264,7 +265,7 @@ class PurchaseOrderLineItem(OrderLineItem): def __str__(self): return "{n} x {part} from {supplier} (for {po})".format( - n=self.quantity, + n=decimal2string(self.quantity), part=self.part.SKU if self.part else 'unknown part', supplier=self.order.supplier.name, po=self.order) @@ -284,7 +285,7 @@ class PurchaseOrderLineItem(OrderLineItem): help_text=_("Supplier part"), ) - received = models.PositiveIntegerField(default=0, help_text=_('Number of items received')) + received = models.DecimalField(decimal_places=5, max_digits=15, default=0, help_text=_('Number of items received')) def remaining(self): """ Calculate the number of items remaining to be received """ diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index d988f20739..d0bd0e3f53 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -1,6 +1,8 @@ {% extends "base.html" %} +{% load i18n %} {% load static %} +{% load inventree_extras %} {% block page_title %} InvenTree | {{ order }} @@ -55,29 +57,29 @@ InvenTree | {{ order }}
-

Purchase Order Details

+

{% trans "Purchase Order Details" %}

PartDescriptionAvailableRequiredAllocatedOn Order{% trans "Part" %}{% trans "Description" %}{% trans "Available" %}{% trans "Required" %}{% trans "Allocated" %}{% trans "On Order" %}
{{ item.part.description }}{{ item.part.total_stock }}{{ item.quantity }}{% decimal item.part.total_stock %}{% decimal item.quantity %} {{ item.allocated }}{{ item.part.on_order }}{% decimal item.part.on_order %}
- + - + - + {% if order.issue_date %} - + {% endif %} {% if order.status == OrderStatus.COMPLETE %} - + {% endif %} @@ -98,16 +100,16 @@ InvenTree | {{ order }}
Supplier{% trans "Supplier" %} {{ order.supplier }}
Status{% trans "Status" %} {% include "order/order_status.html" %}
Created{% trans "Created" %} {{ order.creation_date }}{{ order.created_by }}
Issued{% trans "Issued" %} {{ order.issue_date }}
Received{% trans "Received" %} {{ order.complete_date }}{{ order.received_by }}
- - - - - - + + + + + + {% if not order.status == OrderStatus.PENDING %} - + {% endif %} - + @@ -128,9 +130,9 @@ InvenTree | {{ order }} {% endif %} - + {% if not order.status == OrderStatus.PENDING %} - + {% endif %}
LinePartDescriptionOrder CodeReferenceQuantity{% trans "Line" %}{% trans "Part" %}{% trans "Description" %}{% trans "Order Code" %}{% trans "Reference" %}{% trans "Quantity" %}Received{% trans "Received" %}Note{% trans "Note" %}
Warning: Part has been deleted.{{ line.reference }}{{ line.quantity }}{% decimal line.quantity %}{{ line.received }}{% decimal line.received %} {{ line.notes }} @@ -160,7 +162,7 @@ InvenTree | {{ order }} {% if order.notes %}
-
Notes
+
{% trans "Notes" %}
{{ order.notes }}
{% endif %} diff --git a/InvenTree/part/migrations/0024_auto_20191118_2139.py b/InvenTree/part/migrations/0024_auto_20191118_2139.py new file mode 100644 index 0000000000..95892993b2 --- /dev/null +++ b/InvenTree/part/migrations/0024_auto_20191118_2139.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 21:39 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0023_auto_20190913_1401'), + ] + + operations = [ + migrations.AlterField( + model_name='bomitem', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1.0, help_text='BOM quantity for this BOM item', max_digits=15, validators=[django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/InvenTree/part/migrations/0025_auto_20191118_2316.py b/InvenTree/part/migrations/0025_auto_20191118_2316.py new file mode 100644 index 0000000000..cbdd7be75a --- /dev/null +++ b/InvenTree/part/migrations/0025_auto_20191118_2316.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0024_auto_20191118_2139'), + ] + + operations = [ + migrations.AlterField( + model_name='part', + name='units', + field=models.CharField(blank=True, default='', help_text='Stock keeping units for this part', max_length=20), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index a06d5ea718..809ef0a428 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -53,10 +53,10 @@ class PartCategory(InvenTreeTree): 'stock.StockLocation', related_name="default_categories", null=True, blank=True, on_delete=models.SET_NULL, - help_text='Default location for parts in this category' + help_text=_('Default location for parts in this category') ) - default_keywords = models.CharField(blank=True, max_length=250, help_text='Default keywords for parts in this category') + default_keywords = models.CharField(blank=True, max_length=250, help_text=_('Default keywords for parts in this category')) def get_absolute_url(self): return reverse('category-detail', kwargs={'pk': self.id}) @@ -324,11 +324,11 @@ class Part(models.Model): }) name = models.CharField(max_length=100, blank=False, - help_text='Part name', + help_text=_('Part name'), validators=[validators.validate_part_name] ) - is_template = models.BooleanField(default=False, help_text='Is this part a template part?') + is_template = models.BooleanField(default=False, help_text=_('Is this part a template part?')) variant_of = models.ForeignKey('part.Part', related_name='variants', null=True, blank=True, @@ -337,28 +337,28 @@ class Part(models.Model): 'active': True, }, on_delete=models.SET_NULL, - help_text='Is this part a variant of another part?') + help_text=_('Is this part a variant of another part?')) - description = models.CharField(max_length=250, blank=False, help_text='Part description') + description = models.CharField(max_length=250, blank=False, help_text=_('Part description')) - keywords = models.CharField(max_length=250, blank=True, help_text='Part keywords to improve visibility in search results') + keywords = models.CharField(max_length=250, blank=True, help_text=_('Part keywords to improve visibility in search results')) category = TreeForeignKey(PartCategory, related_name='parts', null=True, blank=True, on_delete=models.DO_NOTHING, - help_text='Part category') + help_text=_('Part category')) - IPN = models.CharField(max_length=100, blank=True, help_text='Internal Part Number') + IPN = models.CharField(max_length=100, blank=True, help_text=_('Internal Part Number')) - revision = models.CharField(max_length=100, blank=True, help_text='Part revision or version number') + revision = models.CharField(max_length=100, blank=True, help_text=_('Part revision or version number')) - URL = InvenTreeURLField(blank=True, help_text='Link to extenal URL') + URL = InvenTreeURLField(blank=True, help_text=_('Link to extenal URL')) image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True) default_location = TreeForeignKey('stock.StockLocation', on_delete=models.SET_NULL, blank=True, null=True, - help_text='Where is this item normally stored?', + help_text=_('Where is this item normally stored?'), related_name='default_parts') def get_default_location(self): @@ -402,30 +402,30 @@ class Part(models.Model): default_supplier = models.ForeignKey(SupplierPart, on_delete=models.SET_NULL, blank=True, null=True, - help_text='Default supplier part', + help_text=_('Default supplier part'), related_name='default_parts') - minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)], help_text='Minimum allowed stock level') + minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)], help_text=_('Minimum allowed stock level')) - units = models.CharField(max_length=20, default="pcs", blank=True, help_text='Stock keeping units for this part') + units = models.CharField(max_length=20, default="", blank=True, help_text=_('Stock keeping units for this part')) - assembly = models.BooleanField(default=False, verbose_name='Assembly', help_text='Can this part be built from other parts?') + assembly = models.BooleanField(default=False, verbose_name='Assembly', help_text=_('Can this part be built from other parts?')) - component = models.BooleanField(default=True, verbose_name='Component', help_text='Can this part be used to build other parts?') + component = models.BooleanField(default=True, verbose_name='Component', help_text=_('Can this part be used to build other parts?')) - trackable = models.BooleanField(default=False, help_text='Does this part have tracking for unique items?') + trackable = models.BooleanField(default=False, help_text=_('Does this part have tracking for unique items?')) - purchaseable = models.BooleanField(default=True, help_text='Can this part be purchased from external suppliers?') + purchaseable = models.BooleanField(default=True, help_text=_('Can this part be purchased from external suppliers?')) - salable = models.BooleanField(default=False, help_text="Can this part be sold to customers?") + salable = models.BooleanField(default=False, help_text=_("Can this part be sold to customers?")) - active = models.BooleanField(default=True, help_text='Is this part active?') + active = models.BooleanField(default=True, help_text=_('Is this part active?')) - virtual = models.BooleanField(default=False, help_text='Is this a virtual part, such as a software product or license?') + virtual = models.BooleanField(default=False, help_text=_('Is this a virtual part, such as a software product or license?')) notes = models.TextField(blank=True) - bom_checksum = models.CharField(max_length=128, blank=True, help_text='Stored BOM checksum') + bom_checksum = models.CharField(max_length=128, blank=True, help_text=_('Stored BOM checksum')) bom_checked_by = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True, related_name='boms_checked') @@ -517,7 +517,7 @@ class Part(models.Model): # 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'): stock = item.sub_part.available_stock - n = int(1.0 * stock / item.quantity) + n = int(stock / item.quantity) if total is None or n < total: total = n @@ -932,9 +932,9 @@ class PartAttachment(models.Model): related_name='attachments') attachment = models.FileField(upload_to=attach_file, - help_text='Select file to attach') + help_text=_('Select file to attach')) - comment = models.CharField(max_length=100, help_text='File comment') + comment = models.CharField(max_length=100, help_text=_('File comment')) @property def basename(self): @@ -994,9 +994,9 @@ class PartParameterTemplate(models.Model): except PartParameterTemplate.DoesNotExist: pass - name = models.CharField(max_length=100, help_text='Parameter Name', unique=True) + name = models.CharField(max_length=100, help_text=_('Parameter Name'), unique=True) - units = models.CharField(max_length=25, help_text='Parameter Units', blank=True) + units = models.CharField(max_length=25, help_text=_('Parameter Units'), blank=True) class PartParameter(models.Model): @@ -1022,11 +1022,11 @@ class PartParameter(models.Model): # Prevent multiple instances of a parameter for a single part unique_together = ('part', 'template') - part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='parameters', help_text='Parent Part') + part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='parameters', help_text=_('Parent Part')) - template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE, related_name='instances', help_text='Parameter Template') + template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE, related_name='instances', help_text=_('Parameter Template')) - data = models.CharField(max_length=500, help_text='Parameter Value') + data = models.CharField(max_length=500, help_text=_('Parameter Value')) class BomItem(models.Model): @@ -1050,7 +1050,7 @@ class BomItem(models.Model): # A link to the parent part # Each part will get a reverse lookup field 'bom_items' part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='bom_items', - help_text='Select parent part', + help_text=_('Select parent part'), limit_choices_to={ 'assembly': True, }) @@ -1058,24 +1058,24 @@ class BomItem(models.Model): # A link to the child item (sub-part) # Each part will get a reverse lookup field 'used_in' sub_part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='used_in', - help_text='Select part to be used in BOM', + help_text=_('Select part to be used in BOM'), limit_choices_to={ 'component': True, }) # Quantity required - quantity = models.PositiveIntegerField(default=1, validators=[MinValueValidator(0)], help_text='BOM quantity for this BOM item') + quantity = models.DecimalField(default=1.0, max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], help_text=_('BOM quantity for this BOM item')) overage = models.CharField(max_length=24, blank=True, validators=[validators.validate_overage], - help_text='Estimated build wastage quantity (absolute or percentage)' + help_text=_('Estimated build wastage quantity (absolute or percentage)') ) - reference = models.CharField(max_length=500, blank=True, help_text='BOM item reference') + reference = models.CharField(max_length=500, blank=True, help_text=_('BOM item reference')) # Note attached to this BOM line item - note = models.CharField(max_length=500, blank=True, help_text='BOM item notes') + note = models.CharField(max_length=500, blank=True, help_text=_('BOM item notes')) - checksum = models.CharField(max_length=128, blank=True, help_text='BOM line checksum') + checksum = models.CharField(max_length=128, blank=True, help_text=_('BOM line checksum')) def get_item_hash(self): """ Calculate the checksum hash of this BOM line item: @@ -1161,7 +1161,7 @@ class BomItem(models.Model): return "{n} x {child} to make {parent}".format( parent=self.part.full_name, child=self.sub_part.full_name, - n=self.quantity) + n=helpers.decimal2string(self.quantity)) def get_overage_quantity(self, quantity): """ Calculate overage quantity diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 47c530fb84..12db3e3e9b 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -1,6 +1,7 @@ {% extends "part/part_base.html" %} {% load static %} {% load i18n %} + {% block details %} {% include 'part/tabs.html' with tab='detail' %} diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index dfb9b2decf..8b11f0ff30 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -1,12 +1,14 @@ {% extends "part/part_app_base.html" %} {% load static %} +{% load i18n %} +{% load inventree_extras %} {% block content %} {% if part.active == False %}
- This part is not active: + {% trans "This part is not active" %}"
{% endif %} {% if part.is_template %} @@ -42,13 +44,13 @@

- {% if part.is_template == False %} {% include "qr_button.html" %} {% if part.active %} - {% if not part.virtual %} @@ -80,13 +82,13 @@ {% if part.IPN %} - + {% endif %} {% if part.URL %} - + {% endif %} @@ -100,25 +102,25 @@
IPN{% trans "IPN" %} {{ part.IPN }}
URL{% trans "URL" %} {{ part.URL }}
- + - - + + {% if not part.is_template %} {% if part.allocation_count > 0 %} - - + + {% endif %} {% if part.on_order > 0 %} - - + + {% endif %} {% endif %} @@ -126,17 +128,17 @@ {% if part.assembly %} - - + + {% if part.quantity_being_built > 0 %} - - + + {% endif %} {% endif %} diff --git a/InvenTree/part/templates/part/tabs.html b/InvenTree/part/templates/part/tabs.html index 23b0f8070c..52630d333f 100644 --- a/InvenTree/part/templates/part/tabs.html +++ b/InvenTree/part/templates/part/tabs.html @@ -1,54 +1,57 @@ +{% load i18n %} +{% load inventree_extras %} + \ No newline at end of file diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index 14a884c2b7..d0497c28e4 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -4,10 +4,18 @@ over and above the built-in Django tags. from django import template from InvenTree import version +from InvenTree.helpers import decimal2string register = template.Library() +@register.simple_tag() +def decimal(x, *args, **kwargs): + """ Simplified rendering of a decimal number """ + + return decimal2string(x) + + @register.simple_tag() def inrange(n, *args, **kwargs): """ Return range(n) for iterating through a numeric quantity """ diff --git a/InvenTree/part/test_api.py b/InvenTree/part/test_api.py index 1b1ef3bc07..f93eb6604d 100644 --- a/InvenTree/part/test_api.py +++ b/InvenTree/part/test_api.py @@ -123,7 +123,7 @@ class PartAPITest(APITestCase): url = reverse('api-bom-item-detail', kwargs={'pk': 3}) response = self.client.get(url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['quantity'], 25) + self.assertEqual(int(float(response.data['quantity'])), 25) # Increase the quantity data = response.data @@ -134,7 +134,7 @@ class PartAPITest(APITestCase): # Check that the quantity was increased and a note added self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data['quantity'], 57) + self.assertEqual(int(float(response.data['quantity'])), 57) self.assertEqual(response.data['note'], 'Added a note') def test_add_bom_item(self): diff --git a/InvenTree/stock/migrations/0016_auto_20191118_2146.py b/InvenTree/stock/migrations/0016_auto_20191118_2146.py new file mode 100644 index 0000000000..d3dbe957ed --- /dev/null +++ b/InvenTree/stock/migrations/0016_auto_20191118_2146.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 21:46 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0015_auto_20190913_1407'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitem', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, max_digits=15, validators=[django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/InvenTree/stock/migrations/0017_auto_20191118_2311.py b/InvenTree/stock/migrations/0017_auto_20191118_2311.py new file mode 100644 index 0000000000..32e6de6cea --- /dev/null +++ b/InvenTree/stock/migrations/0017_auto_20191118_2311.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.5 on 2019-11-18 23:11 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0016_auto_20191118_2146'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitemtracking', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, max_digits=15, validators=[django.core.validators.MinValueValidator(0)]), + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 3f56b2e885..1122d4326c 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -18,6 +18,7 @@ from django.dispatch import receiver from mptt.models import TreeForeignKey +from decimal import Decimal, InvalidOperation from datetime import datetime from InvenTree import helpers @@ -294,43 +295,43 @@ class StockItem(models.Model): ) part = models.ForeignKey('part.Part', on_delete=models.CASCADE, - related_name='stock_items', help_text='Base part', + related_name='stock_items', help_text=_('Base part'), limit_choices_to={ 'is_template': False, 'active': True, }) supplier_part = models.ForeignKey('company.SupplierPart', blank=True, null=True, on_delete=models.SET_NULL, - help_text='Select a matching supplier part for this stock item') + help_text=_('Select a matching supplier part for this stock item')) location = TreeForeignKey(StockLocation, on_delete=models.DO_NOTHING, related_name='stock_items', blank=True, null=True, - help_text='Where is this stock item located?') + help_text=_('Where is this stock item located?')) belongs_to = models.ForeignKey('self', on_delete=models.DO_NOTHING, related_name='owned_parts', blank=True, null=True, - help_text='Is this item installed in another item?') + help_text=_('Is this item installed in another item?')) customer = models.ForeignKey('company.Company', on_delete=models.SET_NULL, related_name='stockitems', blank=True, null=True, - help_text='Item assigned to customer?') + help_text=_('Item assigned to customer?')) serial = models.PositiveIntegerField(blank=True, null=True, - help_text='Serial number for this item') + help_text=_('Serial number for this item')) URL = InvenTreeURLField(max_length=125, blank=True) batch = models.CharField(max_length=100, blank=True, null=True, - help_text='Batch code for this stock item') + help_text=_('Batch code for this stock item')) - quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1) + quantity = models.DecimalField(max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], default=1) updated = models.DateField(auto_now=True, null=True) build = models.ForeignKey( 'build.Build', on_delete=models.SET_NULL, blank=True, null=True, - help_text='Build for this stock item', + help_text=_('Build for this stock item'), related_name='build_outputs', ) @@ -339,7 +340,7 @@ class StockItem(models.Model): on_delete=models.SET_NULL, related_name='stock_items', blank=True, null=True, - help_text='Purchase order for this stock item' + help_text=_('Purchase order for this stock item') ) # last time the stock was checked / counted @@ -350,7 +351,7 @@ class StockItem(models.Model): review_needed = models.BooleanField(default=False) - delete_on_deplete = models.BooleanField(default=True, help_text='Delete this Stock Item when stock is depleted') + delete_on_deplete = models.BooleanField(default=True, help_text=_('Delete this Stock Item when stock is depleted')) status = models.PositiveIntegerField( default=StockStatus.OK, @@ -510,6 +511,11 @@ class StockItem(models.Model): if self.serialized: return + try: + quantity = Decimal(quantity) + except (InvalidOperation, ValueError): + return + # Doesn't make sense for a zero quantity if quantity <= 0: return @@ -549,7 +555,10 @@ class StockItem(models.Model): quantity: If provided, override the quantity (default = total stock quantity) """ - quantity = int(kwargs.get('quantity', self.quantity)) + try: + quantity = Decimal(kwargs.get('quantity', self.quantity)) + except InvalidOperation: + return False if quantity <= 0: return False @@ -599,12 +608,19 @@ class StockItem(models.Model): if self.serialized: return + try: + self.quantity = Decimal(quantity) + except (InvalidOperation, ValueError): + return + if quantity < 0: quantity = 0 self.quantity = quantity - if quantity <= 0 and self.delete_on_deplete and self.can_delete(): + if quantity == 0 and self.delete_on_deplete and self.can_delete(): + + # TODO - Do not actually "delete" stock at this point - instead give it a "DELETED" flag self.delete() return False else: @@ -618,7 +634,10 @@ class StockItem(models.Model): record the date of stocktake """ - count = int(count) + try: + count = Decimal(count) + except InvalidOperation: + return False if count < 0 or self.infinite: return False @@ -646,7 +665,10 @@ class StockItem(models.Model): if self.serialized: return False - quantity = int(quantity) + try: + quantity = Decimal(quantity) + except InvalidOperation: + return False # Ignore amounts that do not make sense if quantity <= 0 or self.infinite: @@ -670,7 +692,10 @@ class StockItem(models.Model): if self.serialized: return False - quantity = int(quantity) + try: + quantity = Decimal(quantity) + except InvalidOperation: + return False if quantity <= 0 or self.infinite: return False @@ -691,7 +716,7 @@ class StockItem(models.Model): sn=self.serial) else: s = '{n} x {part}'.format( - n=self.quantity, + n=helpers.decimal2string(self.quantity), part=self.part.full_name) if self.location: @@ -722,17 +747,17 @@ class StockItemTracking(models.Model): date = models.DateTimeField(auto_now_add=True, editable=False) - title = models.CharField(blank=False, max_length=250, help_text='Tracking entry title') + title = models.CharField(blank=False, max_length=250, help_text=_('Tracking entry title')) - notes = models.CharField(blank=True, max_length=512, help_text='Entry notes') + notes = models.CharField(blank=True, max_length=512, help_text=_('Entry notes')) - URL = InvenTreeURLField(blank=True, help_text='Link to external page for further information') + URL = InvenTreeURLField(blank=True, help_text=_('Link to external page for further information')) user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) system = models.BooleanField(default=False) - quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1) + quantity = models.DecimalField(max_digits=15, decimal_places=5, validators=[MinValueValidator(0)], default=1) # TODO # image = models.ImageField(upload_to=func, max_length=255, null=True, blank=True) diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index 94bf0fd7fb..f6494edd93 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -1,5 +1,6 @@ {% extends "stock/stock_app_base.html" %} {% load static %} +{% load inventree_extras %} {% load i18n %} {% block content %} @@ -86,7 +87,7 @@ {% else %} - + {% endif %} {% if item.batch %} diff --git a/InvenTree/stock/tests.py b/InvenTree/stock/tests.py index 95eb1002ad..2f840833a3 100644 --- a/InvenTree/stock/tests.py +++ b/InvenTree/stock/tests.py @@ -245,7 +245,7 @@ class StockTest(TestCase): w1 = StockItem.objects.get(pk=100) w2 = StockItem.objects.get(pk=101) - # Take 25 units from w1 + # Take 25 units from w1 (there are only 10 in stock) w1.take_stock(30, None, notes='Took 30') # Get from database again diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index a503efaba4..dc56aa87ff 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -20,6 +20,8 @@ from InvenTree.views import QRCodeView from InvenTree.helpers import str2bool, DownloadFile, GetExportFormats from InvenTree.helpers import ExtractSerialNumbers + +from decimal import Decimal, InvalidOperation from datetime import datetime from company.models import Company @@ -91,7 +93,7 @@ class StockLocationEdit(AjaxUpdateView): form_class = EditStockLocationForm context_object_name = 'location' ajax_template_name = 'modal_form.html' - ajax_form_title = 'Edit Stock Location' + ajax_form_title = _('Edit Stock Location') def get_form(self): """ Customize form data for StockLocation editing. @@ -115,7 +117,7 @@ class StockLocationEdit(AjaxUpdateView): class StockLocationQRCode(QRCodeView): """ View for displaying a QR code for a StockLocation object """ - ajax_form_title = "Stock Location QR code" + ajax_form_title = _("Stock Location QR code") def get_qr_data(self): """ Generate QR code data for the StockLocation """ @@ -130,7 +132,7 @@ class StockExportOptions(AjaxView): """ Form for selecting StockExport options """ model = StockLocation - ajax_form_title = 'Stock Export Options' + ajax_form_title = _('Stock Export Options') form_class = ExportOptionsForm def post(self, request, *args, **kwargs): @@ -238,7 +240,7 @@ class StockExport(AjaxView): class StockItemQRCode(QRCodeView): """ View for displaying a QR code for a StockItem object """ - ajax_form_title = "Stock Item QR Code" + ajax_form_title = _("Stock Item QR Code") def get_qr_data(self): """ Generate QR code data for the StockItem """ @@ -261,7 +263,7 @@ class StockAdjust(AjaxView, FormMixin): """ ajax_template_name = 'stock/stock_adjust.html' - ajax_form_title = 'Adjust Stock' + ajax_form_title = _('Adjust Stock') form_class = AdjustStockForm stock_items = [] @@ -398,8 +400,9 @@ class StockAdjust(AjaxView, FormMixin): valid = form.is_valid() for item in self.stock_items: + try: - item.new_quantity = int(item.new_quantity) + item.new_quantity = Decimal(item.new_quantity) except ValueError: item.error = _('Must enter integer value') valid = False @@ -543,7 +546,7 @@ class StockAdjust(AjaxView, FormMixin): if destination == item.location and item.new_quantity == item.quantity: continue - item.move(destination, note, self.request.user, quantity=int(item.new_quantity)) + item.move(destination, note, self.request.user, quantity=item.new_quantity) count += 1 @@ -582,7 +585,7 @@ class StockItemEdit(AjaxUpdateView): form_class = EditStockItemForm context_object_name = 'item' ajax_template_name = 'modal_form.html' - ajax_form_title = 'Edit Stock Item' + ajax_form_title = _('Edit Stock Item') def get_form(self): """ Get form for StockItem editing. @@ -618,7 +621,7 @@ class StockLocationCreate(AjaxCreateView): form_class = EditStockLocationForm context_object_name = 'location' ajax_template_name = 'modal_form.html' - ajax_form_title = 'Create new Stock Location' + ajax_form_title = _('Create new Stock Location') def get_initial(self): initials = super(StockLocationCreate, self).get_initial().copy() @@ -639,7 +642,7 @@ class StockItemSerialize(AjaxUpdateView): model = StockItem ajax_template_name = 'stock/item_serialize.html' - ajax_form_title = 'Serialize Stock' + ajax_form_title = _('Serialize Stock') form_class = SerializeStockForm def get_initial(self): @@ -719,7 +722,7 @@ class StockItemCreate(AjaxCreateView): form_class = CreateStockItemForm context_object_name = 'item' ajax_template_name = 'modal_form.html' - ajax_form_title = 'Create new Stock Item' + ajax_form_title = _('Create new Stock Item') def get_form(self): """ Get form for StockItem creation. @@ -783,7 +786,7 @@ class StockItemCreate(AjaxCreateView): try: original = StockItem.objects.get(pk=item_to_copy) initials = model_to_dict(original) - self.ajax_form_title = "Copy Stock Item" + self.ajax_form_title = _("Copy Stock Item") except StockItem.DoesNotExist: initials = super(StockItemCreate, self).get_initial().copy() @@ -828,11 +831,12 @@ class StockItemCreate(AjaxCreateView): part_id = form['part'].value() try: part = Part.objects.get(id=part_id) - quantity = int(form['quantity'].value()) - except (Part.DoesNotExist, ValueError): + quantity = Decimal(form['quantity'].value()) + except (Part.DoesNotExist, ValueError, InvalidOperation): part = None quantity = 1 valid = False + form.errors['quantity'] = [_('Invalid quantity')] if part is None: form.errors['part'] = [_('Invalid part selection')] @@ -914,7 +918,7 @@ class StockLocationDelete(AjaxDeleteView): success_url = '/stock' ajax_template_name = 'stock/location_delete.html' context_object_name = 'location' - ajax_form_title = 'Delete Stock Location' + ajax_form_title = _('Delete Stock Location') class StockItemDelete(AjaxDeleteView): @@ -927,7 +931,7 @@ class StockItemDelete(AjaxDeleteView): success_url = '/stock/' ajax_template_name = 'stock/item_delete.html' context_object_name = 'item' - ajax_form_title = 'Delete Stock Item' + ajax_form_title = _('Delete Stock Item') class StockItemTrackingDelete(AjaxDeleteView): @@ -938,7 +942,7 @@ class StockItemTrackingDelete(AjaxDeleteView): model = StockItemTracking ajax_template_name = 'stock/tracking_delete.html' - ajax_form_title = 'Delete Stock Tracking Entry' + ajax_form_title = _('Delete Stock Tracking Entry') class StockTrackingIndex(ListView): @@ -955,7 +959,7 @@ class StockItemTrackingEdit(AjaxUpdateView): """ View for editing a StockItemTracking object """ model = StockItemTracking - ajax_form_title = 'Edit Stock Tracking Entry' + ajax_form_title = _('Edit Stock Tracking Entry') form_class = TrackingEntryForm @@ -964,7 +968,7 @@ class StockItemTrackingCreate(AjaxCreateView): """ model = StockItemTracking - ajax_form_title = "Add Stock Tracking Entry" + ajax_form_title = _("Add Stock Tracking Entry") form_class = TrackingEntryForm def post(self, request, *args, **kwargs):
-

Available Stock

+

{% trans "Available Stock" %}

{{ part.available_stock }} {{ part.units }}

{% decimal part.available_stock %} {{ part.units }}

In Stock{{ part.total_stock }}{% trans "In Stock" %}{% decimal part.total_stock %}
Allocated{{ part.allocation_count }}{% trans "Allocated" %}{% decimal part.allocation_count %}
On Order{{ part.on_order }}{% trans "On Order" %}{% decimal part.on_order %}
- Build Status + {% trans "Build Status" %}
Can Build{{ part.can_build }}{% trans "Can Build" %}{% decimal part.can_build %}
Underway{{ part.quantity_being_built }}{% trans "Underway" %}{% decimal part.quantity_being_built %}
{% trans "Quantity" %}{{ item.quantity }}{% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}