From 86e675dbbdeb62be086705c4db9fea1ce9818360 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 28 Aug 2020 10:49:49 +1000 Subject: [PATCH 01/13] Make checkbox field non-switchable for stock table --- InvenTree/templates/js/stock.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InvenTree/templates/js/stock.html b/InvenTree/templates/js/stock.html index 9393b29739..f142f3f59f 100644 --- a/InvenTree/templates/js/stock.html +++ b/InvenTree/templates/js/stock.html @@ -264,6 +264,7 @@ function loadStockTable(table, options) { queryParams: filters, customSort: customGroupSorter, groupBy: true, + name: 'stock', original: original, showColumns: true, groupByField: options.groupByField || 'part', @@ -405,6 +406,7 @@ function loadStockTable(table, options) { checkbox: true, title: '{% trans "Select" %}', searchable: false, + switchable: false, }, { field: 'pk', From 9c2e959ab0d9b02b44c925c9547070a47a501861 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 28 Aug 2020 10:50:43 +1000 Subject: [PATCH 02/13] Add function to turn a set of visible columns into a settings string for saving to session --- .../InvenTree/static/script/inventree/tables.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index e319aa8440..079eee3724 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -80,6 +80,21 @@ function reloadTable(table, filters) { } +function visibleColumnString(columns) { + /* Generate a list of "visible" columns to save to file. */ + + var fields = []; + + columns.forEach(function(column) { + if (column.switchable && column.visible) { + fields.push(column.field); + } + }); + + return fields.join(','); +} + + /* Wrapper function for bootstrapTable. * Sets some useful defaults, and manage persistent settings. */ From 7829e3654ce5187362f5cec5a453ba1be7e876c0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 28 Aug 2020 10:51:55 +1000 Subject: [PATCH 03/13] Add callback when a column is shown / hidden --- .../static/script/inventree/tables.js | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index 079eee3724..34f8824412 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -100,6 +100,8 @@ function visibleColumnString(columns) { */ $.fn.inventreeTable = function(options) { + var table = this; + var tableName = options.name || 'table'; var varName = tableName + '-pagesize'; @@ -110,14 +112,51 @@ $.fn.inventreeTable = function(options) { options.rememberOrder = true; options.sortable = true; options.search = true; + options.showColumns = true; // Callback to save pagination data options.onPageChange = function(number, size) { inventreeSave(varName, size); }; + // Add a callback when the table is loaded + table.on('load-success.bs.table', function() { + + // Load visible column list + var visibleColumns = inventreeLoad(`table_columns_${tableName}`, null); + + // If a set of visible columns has been saved, load! + if (visibleColumns) { + var columns = visibleColumns.split(","); + + // Which columns are currently visible? + var visible = table.bootstrapTable('getVisibleColumns'); + + visible.forEach(function(column) { + // Visible field should *not* be visible! (hide it!) + if (!columns.includes(visible.field)) { + table.bootstrapTable('hideColumn', visible.field); + } + }); + } + }); + + // Callback when a column is changed + options.onColumnSwitch = function(field, checked) { + console.log(`${field} -> ${checked}`); + + var columns = table.bootstrapTable('getVisibleColumns'); + + var text = visibleColumnString(columns); + + // Save visible columns + inventreeSave(`table_columns_${tableName}`, text); + + console.log('saving: ' + text); + }; + // Standard options for all tables - this.bootstrapTable(options); + table.bootstrapTable(options); } function customGroupSorter(sortName, sortOrder, sortData) { From 07f7b46a8a4cb172bfed7a4f6f4d00fb5803fa4b Mon Sep 17 00:00:00 2001 From: Ben Charlton Date: Fri, 28 Aug 2020 20:38:16 +0100 Subject: [PATCH 04/13] Fix invoke pty error when running 'invoke superuser' --- tasks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasks.py b/tasks.py index 3d92cec5c4..b7bda95033 100644 --- a/tasks.py +++ b/tasks.py @@ -47,7 +47,7 @@ def managePyPath(): return os.path.join(managePyDir(), 'manage.py') -def manage(c, cmd): +def manage(c, cmd, pty=False): """ Runs a given command against django's "manage.py" script. @@ -59,7 +59,7 @@ def manage(c, cmd): c.run('cd {path} && python3 manage.py {cmd}'.format( path=managePyDir(), cmd=cmd - )) + ), pty=pty) @task(help={'length': 'Length of secret key (default=50)'}) def key(c, length=50, force=False): @@ -106,7 +106,7 @@ def superuser(c): Create a superuser (admin) account for the database. """ - manage(c, 'createsuperuser') + manage(c, 'createsuperuser', pty=True) @task def migrate(c): From 5c4781b5b4910330b8f7f405f3f492a18cffe984 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 19:13:24 +1000 Subject: [PATCH 05/13] Order: Improve help text(s) --- .../migrations/0036_auto_20200831_0912.py | 35 +++++++++++++++++++ InvenTree/order/models.py | 12 +++---- InvenTree/report/models.py | 2 +- 3 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 InvenTree/order/migrations/0036_auto_20200831_0912.py diff --git a/InvenTree/order/migrations/0036_auto_20200831_0912.py b/InvenTree/order/migrations/0036_auto_20200831_0912.py new file mode 100644 index 0000000000..1329d0a8d5 --- /dev/null +++ b/InvenTree/order/migrations/0036_auto_20200831_0912.py @@ -0,0 +1,35 @@ +# Generated by Django 3.0.7 on 2020-08-31 09:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0023_auto_20200808_0715'), + ('order', '0035_auto_20200513_0016'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorder', + name='complete_date', + field=models.DateField(blank=True, help_text='Date order was completed', null=True), + ), + migrations.AlterField( + model_name='purchaseorder', + name='issue_date', + field=models.DateField(blank=True, help_text='Date order was issued', null=True), + ), + migrations.AlterField( + model_name='purchaseorder', + name='supplier', + field=models.ForeignKey(help_text='Company from which the items are being ordered', limit_choices_to={'is_supplier': True}, on_delete=django.db.models.deletion.CASCADE, related_name='purchase_orders', to='company.Company'), + ), + migrations.AlterField( + model_name='salesorder', + name='customer', + field=models.ForeignKey(help_text='Company to which the items are being sold', limit_choices_to={'is_customer': True}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sales_orders', to='company.Company'), + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index b607d314a0..7d561b95ba 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -137,7 +137,7 @@ class PurchaseOrder(Order): return "PO {ref} - {company}".format(ref=self.reference, company=self.supplier.name) status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(), - help_text='Purchase order status') + help_text=_('Purchase order status')) supplier = models.ForeignKey( Company, on_delete=models.CASCADE, @@ -145,7 +145,7 @@ class PurchaseOrder(Order): 'is_supplier': True, }, related_name='purchase_orders', - help_text=_('Supplier') + help_text=_('Company from which the items are being ordered') ) supplier_reference = models.CharField(max_length=64, blank=True, help_text=_("Supplier order reference code")) @@ -157,9 +157,9 @@ class PurchaseOrder(Order): related_name='+' ) - issue_date = models.DateField(blank=True, null=True) + issue_date = models.DateField(blank=True, null=True, help_text=_('Date order was issued')) - complete_date = models.DateField(blank=True, null=True) + complete_date = models.DateField(blank=True, null=True, help_text=_('Date order was completed')) def get_absolute_url(self): return reverse('po-detail', kwargs={'pk': self.id}) @@ -311,11 +311,11 @@ class SalesOrder(Order): null=True, limit_choices_to={'is_customer': True}, related_name='sales_orders', - help_text=_("Customer"), + help_text=_("Company to which the items are being sold"), ) status = models.PositiveIntegerField(default=SalesOrderStatus.PENDING, choices=SalesOrderStatus.items(), - help_text='Purchase order status') + help_text=_('Purchase order status')) customer_reference = models.CharField(max_length=64, blank=True, help_text=_("Customer order reference code")) diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py index bba8e50d3d..a5264f7b2b 100644 --- a/InvenTree/report/models.py +++ b/InvenTree/report/models.py @@ -127,7 +127,7 @@ class ReportTemplateBase(models.Model): except TexError: return TexResponse(rendered, filename="error.tex") else: - return ValidationError("Enable LaTeX support in config.yaml") + raise ValidationError("Enable LaTeX support in config.yaml") elif self.extension in ['.htm', '.html']: # Render HTML template to PDF wp = WeasyprintReportMixin(request, self.template_name, **kwargs) From eabb99053c96ad43442f772a954313ea629a7d54 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 19:20:16 +1000 Subject: [PATCH 06/13] Update requirements.txt --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3687341166..041d349c66 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,4 +23,5 @@ rapidfuzz==0.7.6 # Fuzzy string matching django-stdimage==5.1.1 # Advanced ImageField management django-tex==1.1.7 # LaTeX PDF export django-weasyprint==1.0.1 # HTML PDF export -django-debug-toolbar==2.2 # Debug / profiling toolbar \ No newline at end of file +django-debug-toolbar==2.2 # Debug / profiling toolbar +inventree # Install the latest version of the InvenTree API python library \ No newline at end of file From 8615cad711e201f0082efe0722e17d48dae94b84 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 20:08:07 +1000 Subject: [PATCH 07/13] Stock: Fix serializers.py - Use of read_only PrimaryKeyRelatedField was breaking POST via API --- InvenTree/stock/api.py | 4 ++-- InvenTree/stock/serializers.py | 18 +----------------- requirements.txt | 1 + 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 4368f654cf..7741c67129 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -186,7 +186,7 @@ class StockCount(StockAdjust): class StockAdd(StockAdjust): """ - Endpoint for adding stock + Endpoint for adding a quantity of stock to an existing StockItem """ def post(self, request, *args, **kwargs): @@ -204,7 +204,7 @@ class StockAdd(StockAdjust): class StockRemove(StockAdjust): """ - Endpoint for removing stock. + Endpoint for removing a quantity of stock from an existing StockItem. """ def post(self, request, *args, **kwargs): diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index bed3f8f7c1..cccc138523 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -99,26 +99,10 @@ class StockItemSerializer(InvenTreeModelSerializer): return queryset - belongs_to = serializers.PrimaryKeyRelatedField(read_only=True) - - build_order = serializers.PrimaryKeyRelatedField(read_only=True) - - customer = serializers.PrimaryKeyRelatedField(read_only=True) - - location = serializers.PrimaryKeyRelatedField(read_only=True) - - in_stock = serializers.BooleanField(read_only=True) - - sales_order = serializers.PrimaryKeyRelatedField(read_only=True) - status_text = serializers.CharField(source='get_status_display', read_only=True) - - supplier_part = serializers.PrimaryKeyRelatedField(read_only=True) - + supplier_part_detail = SupplierPartSerializer(source='supplier_part', many=False, read_only=True) - part = serializers.PrimaryKeyRelatedField(read_only=True) - part_detail = PartBriefSerializer(source='part', many=False, read_only=True) location_detail = LocationBriefSerializer(source='location', many=False, read_only=True) diff --git a/requirements.txt b/requirements.txt index 041d349c66..38b5a37b6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,4 +24,5 @@ django-stdimage==5.1.1 # Advanced ImageField management django-tex==1.1.7 # LaTeX PDF export django-weasyprint==1.0.1 # HTML PDF export django-debug-toolbar==2.2 # Debug / profiling toolbar + inventree # Install the latest version of the InvenTree API python library \ No newline at end of file From 59e7474f75523e9c9c8ebd299997caa650816d6b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 20:09:43 +1000 Subject: [PATCH 08/13] Stock: More unit tests - Add some more tests (would have caught a bug that was there already, darn it) --- InvenTree/stock/test_api.py | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index cd598e8538..47f2e5fcb1 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -81,6 +81,59 @@ class StockItemTest(StockAPITestCase): response = self.client.get(self.list_url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) + def test_stock_item_create(self): + """ + Test creation of a StockItem via the API + """ + + # POST with an empty part reference + + response = self.client.post( + self.list_url, + data={ + 'quantity': 10, + 'location': 1 + } + ) + + self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST) + + # POST with an invalid part reference + + response = self.client.post( + self.list_url, + data={ + 'quantity': 10, + 'location': 1, + 'part': 10000000, + } + ) + + self.assertContains(response, 'does not exist', status_code=status.HTTP_400_BAD_REQUEST) + + # POST without quantity + response = self.client.post( + self.list_url, + data={ + 'part': 1, + 'location': 1, + } + ) + + self.assertContains(response, 'This field is required', status_code=status.HTTP_400_BAD_REQUEST) + + # POST with quantity and part and location + response = self.client.post( + self.list_url, + data={ + 'part': 1, + 'location': 1, + 'quantity': 10, + } + ) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + class StocktakeTest(StockAPITestCase): """ From 97ed70502c98bb0ed853dd4deeaa70b3a670cb1a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 20:42:11 +1000 Subject: [PATCH 09/13] Fix function which hides table columns based on saved selections --- .../static/script/inventree/tables.js | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index 34f8824412..be0e1e6325 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -119,28 +119,6 @@ $.fn.inventreeTable = function(options) { inventreeSave(varName, size); }; - // Add a callback when the table is loaded - table.on('load-success.bs.table', function() { - - // Load visible column list - var visibleColumns = inventreeLoad(`table_columns_${tableName}`, null); - - // If a set of visible columns has been saved, load! - if (visibleColumns) { - var columns = visibleColumns.split(","); - - // Which columns are currently visible? - var visible = table.bootstrapTable('getVisibleColumns'); - - visible.forEach(function(column) { - // Visible field should *not* be visible! (hide it!) - if (!columns.includes(visible.field)) { - table.bootstrapTable('hideColumn', visible.field); - } - }); - } - }); - // Callback when a column is changed options.onColumnSwitch = function(field, checked) { console.log(`${field} -> ${checked}`); @@ -151,12 +129,34 @@ $.fn.inventreeTable = function(options) { // Save visible columns inventreeSave(`table_columns_${tableName}`, text); - - console.log('saving: ' + text); }; // Standard options for all tables table.bootstrapTable(options); + + // Load visible column list from memory + // Load visible column list + var visibleColumns = inventreeLoad(`table_columns_${tableName}`, null); + + // If a set of visible columns has been saved, load! + if (visibleColumns) { + var columns = visibleColumns.split(","); + + // Which columns are currently visible? + var visible = table.bootstrapTable('getVisibleColumns'); + + if (visible) { + visible.forEach(function(column) { + + // Visible field should *not* be visible! (hide it!) + if (column.switchable && !columns.includes(column.field)) { + table.bootstrapTable('hideColumn', column.field); + } + }); + } else { + console.log('Could not get list of visible columns!'); + } + } } function customGroupSorter(sortName, sortOrder, sortData) { From 672936e2d484c814d4e9031a947d7f4a39eeffe1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 21:55:01 +1000 Subject: [PATCH 10/13] Update many tables --- InvenTree/order/templates/order/purchase_order_detail.html | 2 ++ InvenTree/order/templates/order/sales_order_detail.html | 1 + InvenTree/part/templates/part/used_in.html | 1 + InvenTree/templates/InvenTree/settings/currency.html | 1 + InvenTree/templates/InvenTree/settings/part.html | 1 + InvenTree/templates/js/bom.html | 2 ++ InvenTree/templates/js/build.html | 2 ++ InvenTree/templates/js/company.html | 6 ++++++ InvenTree/templates/js/order.html | 4 ++++ InvenTree/templates/js/part.html | 2 ++ InvenTree/templates/js/stock.html | 2 ++ 11 files changed, 24 insertions(+) diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index de066500b2..9b9eddb887 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -127,6 +127,7 @@ function setupCallbacks() { $("#po-table").inventreeTable({ onPostBody: setupCallbacks, + name: 'purchaseorder', formatNoMatches: function() { return "{% trans 'No line items found' %}"; }, queryParams: { order: {{ order.id }}, @@ -138,6 +139,7 @@ $("#po-table").inventreeTable({ field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'part', diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 75c5fc3d7b..b6cc761cc7 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -190,6 +190,7 @@ $("#so-lines-table").inventreeTable({ field: 'pk', title: 'ID', visible: false, + switchable: false, }, { sortable: true, diff --git a/InvenTree/part/templates/part/used_in.html b/InvenTree/part/templates/part/used_in.html index ce0491a165..3a6605847e 100644 --- a/InvenTree/part/templates/part/used_in.html +++ b/InvenTree/part/templates/part/used_in.html @@ -29,6 +29,7 @@ field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'part_detail', diff --git a/InvenTree/templates/InvenTree/settings/currency.html b/InvenTree/templates/InvenTree/settings/currency.html index 9c602a67fc..c585011ecd 100644 --- a/InvenTree/templates/InvenTree/settings/currency.html +++ b/InvenTree/templates/InvenTree/settings/currency.html @@ -37,6 +37,7 @@ field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'symbol', diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 49631cd67d..5eba81a72a 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -31,6 +31,7 @@ field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'name', diff --git a/InvenTree/templates/js/bom.html b/InvenTree/templates/js/bom.html index 122b1b7ba8..cab2a08b13 100644 --- a/InvenTree/templates/js/bom.html +++ b/InvenTree/templates/js/bom.html @@ -111,6 +111,7 @@ function loadBomTable(table, options) { field: 'pk', title: 'ID', visible: false, + switchable: false, }, ]; @@ -320,6 +321,7 @@ function loadBomTable(table, options) { parentIdField: 'parentId', treeShowField: 'sub_part', showColumns: true, + name: 'bom', sortable: true, search: true, rowStyle: function(row, index) { diff --git a/InvenTree/templates/js/build.html b/InvenTree/templates/js/build.html index b48e6a2a09..8682e9bd81 100644 --- a/InvenTree/templates/js/build.html +++ b/InvenTree/templates/js/build.html @@ -21,12 +21,14 @@ function loadBuildTable(table, options) { url: options.url, queryParams: filters, groupBy: false, + name: 'builds', original: params, columns: [ { field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'title', diff --git a/InvenTree/templates/js/company.html b/InvenTree/templates/js/company.html index 8b278e2a21..ef80070d99 100644 --- a/InvenTree/templates/js/company.html +++ b/InvenTree/templates/js/company.html @@ -27,16 +27,20 @@ function loadCompanyTable(table, url, options={}) { queryParams: filters, groupBy: false, formatNoMatches: function() { return "{% trans "No company information found" %}"; }, + showColumns: true, + name: 'company', columns: [ { field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'name', title: '{% trans "Company" %}', sortable: true, + switchable: false, formatter: function(value, row, index, field) { var html = imageHoverIcon(row.image) + renderLink(value, row.url); @@ -97,11 +101,13 @@ function loadSupplierPartTable(table, url, options) { url: url, method: 'get', queryParams: filters, + name: 'supplierparts', groupBy: false, formatNoMatches: function() { return "{% trans "No supplier parts found" %}"; }, columns: [ { checkbox: true, + switchable: false, }, { sortable: true, diff --git a/InvenTree/templates/js/order.html b/InvenTree/templates/js/order.html index 17bd67cabb..c16b40583c 100644 --- a/InvenTree/templates/js/order.html +++ b/InvenTree/templates/js/order.html @@ -121,6 +121,7 @@ function loadPurchaseOrderTable(table, options) { $(table).inventreeTable({ url: options.url, queryParams: filters, + name: 'purchaseorder', groupBy: false, original: options.params, formatNoMatches: function() { return "{% trans "No purchase orders found" %}"; }, @@ -129,6 +130,7 @@ function loadPurchaseOrderTable(table, options) { field: 'pk', title: 'ID', visible: false, + switchable: false, }, { sortable: true, @@ -194,6 +196,7 @@ function loadSalesOrderTable(table, options) { $(table).inventreeTable({ url: options.url, queryParams: filters, + name: 'salesorder', groupBy: false, original: options.params, formatNoMatches: function() { return "{% trans "No sales orders found" %}"; }, @@ -202,6 +205,7 @@ function loadSalesOrderTable(table, options) { field: 'pk', title: 'ID', visible: false, + switchable: false, }, { sortable: true, diff --git a/InvenTree/templates/js/part.html b/InvenTree/templates/js/part.html index c9901cdb68..a1c3283c1c 100644 --- a/InvenTree/templates/js/part.html +++ b/InvenTree/templates/js/part.html @@ -237,6 +237,7 @@ function loadPartTable(table, url, options={}) { method: 'get', queryParams: filters, groupBy: false, + name: 'part', original: params, formatNoMatches: function() { return "{% trans "No parts found" %}"; }, columns: columns, @@ -338,6 +339,7 @@ function loadPartTestTemplateTable(table, options) { }, url: "{% url 'api-part-test-template-list' %}", queryParams: filters, + name: 'testtemplate', original: original, columns: [ { diff --git a/InvenTree/templates/js/stock.html b/InvenTree/templates/js/stock.html index f142f3f59f..bb0673c16d 100644 --- a/InvenTree/templates/js/stock.html +++ b/InvenTree/templates/js/stock.html @@ -73,6 +73,7 @@ function loadStockTestResultsTable(table, options) { table.inventreeTable({ url: "{% url 'api-part-test-template-list' %}", method: 'get', + name: 'testresult', formatNoMatches: function() { return "{% trans 'No test results found' %}"; }, @@ -84,6 +85,7 @@ function loadStockTestResultsTable(table, options) { field: 'pk', title: 'ID', visible: false, + switchable: false, }, { field: 'test_name', From cd8214ff4a7c530440432d1196af1e25ee276263 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 22:26:46 +1000 Subject: [PATCH 11/13] Part: add function to get part attachments for *all* parents of a part --- InvenTree/part/models.py | 14 ++++++++++++++ InvenTree/part/templates/part/attachments.html | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index e5b035f856..c5da47b33e 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1087,6 +1087,20 @@ class Part(MPTTModel): return n + @property + def part_attachments(self): + """ + Return *all* attachments for this part, + potentially including attachments for template parts + above this one. + """ + + ancestors = self.get_ancestors(include_self=True) + + attachments = PartAttachment.objects.filter(part__in=ancestors) + + return attachments + def sales_orders(self): """ Return a list of sales orders which reference this part """ diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index 049ef0cd7a..aa31cd3f32 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -9,7 +9,7 @@
-{% include "attachment_table.html" with attachments=part.attachments.all %} +{% include "attachment_table.html" with attachments=part.part_attachments %} {% endblock %} From 73892e894e064c2a30866737c763065cf1bc26e4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 31 Aug 2020 22:30:38 +1000 Subject: [PATCH 12/13] Refactoring --- InvenTree/part/models.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index c5da47b33e..26dd04ac52 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1080,12 +1080,7 @@ class Part(MPTTModel): """ - n = self.attachments.count() - - if self.variant_of: - n += self.variant_of.attachments.count() - - return n + return self.part_attachments.count() @property def part_attachments(self): From ffbdb0317f30713540471d04cea6c31552469fc0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 1 Sep 2020 12:43:37 +1000 Subject: [PATCH 13/13] Add "focus" option when displaying a modal form --- InvenTree/InvenTree/static/script/inventree/modals.js | 5 +++++ InvenTree/stock/templates/stock/item_tests.html | 2 ++ 2 files changed, 7 insertions(+) diff --git a/InvenTree/InvenTree/static/script/inventree/modals.js b/InvenTree/InvenTree/static/script/inventree/modals.js index a17cee0d2c..1cb5346a68 100644 --- a/InvenTree/InvenTree/static/script/inventree/modals.js +++ b/InvenTree/InvenTree/static/script/inventree/modals.js @@ -469,6 +469,9 @@ function openModal(options) { $(modal).on('shown.bs.modal', function() { $(modal + ' .modal-form-content').scrollTop(0); + if (options.focus) { + getFieldByName(modal, options.focus).focus(); + } }); // Prevent 'enter' key from submitting the form using the normal method @@ -745,6 +748,7 @@ function launchModalForm(url, options = {}) { * after_render - Callback function to run after form is rendered * secondary - List of secondary modals to attach * callback - List of callback functions to attach to inputs + * focus - Select which field to focus on by default */ var modal = options.modal || '#modal-form'; @@ -763,6 +767,7 @@ function launchModalForm(url, options = {}) { modal: modal, submit_text: submit_text, close_text: close_text, + focus: options.focus }); }, success: function(response) { diff --git a/InvenTree/stock/templates/stock/item_tests.html b/InvenTree/stock/templates/stock/item_tests.html index 10bb0950e4..6bc120711d 100644 --- a/InvenTree/stock/templates/stock/item_tests.html +++ b/InvenTree/stock/templates/stock/item_tests.html @@ -73,6 +73,7 @@ $("#add-test-result").click(function() { stock_item: {{ item.id }}, }, success: reloadTable, + focus: 'test', } ); }); @@ -89,6 +90,7 @@ $("#test-result-table").on('click', '.button-test-add', function() { test: test_name }, success: reloadTable, + focus: 'value', } ); });