From d2b9993e96eb6658be2060490630033bb89a4404 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Sep 2021 12:04:25 +1000 Subject: [PATCH 01/10] Fix form filters for "default_supplier" --- InvenTree/templates/js/translated/part.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 9abbd2a0b9..e74b6fd743 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -94,7 +94,12 @@ function partFields(options={}) { }, default_location: { }, - default_supplier: {}, + default_supplier: { + filters: { + part_detail: true, + supplier_detail: true, + } + }, default_expiry: { icon: 'fa-calendar-alt', }, @@ -315,6 +320,9 @@ function editPart(pk) { edit: true }); + // Filter supplied parts by the Part ID + fields.default_supplier.filters.part = pk; + var groups = partGroups({}); constructForm(url, { From f53aac0784f158ce2508e1810b20262abf09f6f5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 24 Sep 2021 12:04:36 +1000 Subject: [PATCH 02/10] Remove "default_supplier" field when duplicating a part --- InvenTree/templates/js/translated/part.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index e74b6fd743..6e8c02c0b1 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -346,6 +346,9 @@ function duplicatePart(pk, options={}) { duplicate: pk, }); + // Remove "default_supplier" field + delete fields['default_supplier']; + // If we are making a "variant" part if (options.variant) { From beaa93f9b577515b8fd876d8e8e7d72a0d12eb1a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Sep 2021 11:41:24 +1000 Subject: [PATCH 03/10] Fix ?display= URLs for part stock view --- InvenTree/templates/js/translated/bom.js | 2 +- InvenTree/templates/js/translated/part.js | 2 +- InvenTree/templates/js/translated/stock.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js index bcfa7ef5ff..8f571df02e 100644 --- a/InvenTree/templates/js/translated/bom.js +++ b/InvenTree/templates/js/translated/bom.js @@ -271,7 +271,7 @@ function loadBomTable(table, options) { sortable: true, formatter: function(value, row) { - var url = `/part/${row.sub_part_detail.pk}/?display=stock`; + var url = `/part/${row.sub_part_detail.pk}/?display=part-stock`; var text = value; if (value == null || value <= 0) { diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 6e8c02c0b1..afd1b4def8 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -539,7 +539,7 @@ function loadPartVariantTable(table, partId, options={}) { field: 'in_stock', title: '{% trans "Stock" %}', formatter: function(value, row) { - return renderLink(value, `/part/${row.pk}/?display=stock`); + return renderLink(value, `/part/${row.pk}/?display=part-stock`); } } ]; diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index e35831624e..17c2598d1b 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -1019,7 +1019,7 @@ function loadStockTable(table, options) { return '-'; } - var link = `/supplier-part/${row.supplier_part}/?display=stock`; + var link = `/supplier-part/${row.supplier_part}/?display=part-stock`; var text = ''; From ef01bdff07e818fca2d386b790461d78cad82ce6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Sep 2021 11:42:47 +1000 Subject: [PATCH 04/10] Fix links in part table --- InvenTree/templates/js/translated/part.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index afd1b4def8..aba3c46330 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -945,7 +945,7 @@ function loadPartTable(table, url, options={}) { title: '{% trans "Stock" %}', searchable: false, formatter: function(value, row) { - var link = 'stock'; + var link = '?display=part-stock'; if (value) { // There IS stock available for this part @@ -958,17 +958,17 @@ function loadPartTable(table, url, options={}) { } else if (row.on_order) { // There is no stock available, but stock is on order value = `0{% trans "On Order" %}: ${row.on_order}`; - link = 'orders'; + link = '?display=purchase-orders'; } else if (row.building) { // There is no stock available, but stock is being built value = `0{% trans "Building" %}: ${row.building}`; - link = 'builds'; + link = '?display=build-orders'; } else { // There is no stock available value = `0{% trans "No Stock" %}`; } - return renderLink(value, `/part/${row.pk}/${link}/`); + return renderLink(value, `/part/${row.pk}/${link}`); } }; From 26e3dbd9d0ce56ff32a520b40fe93eaa083de394 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 27 Sep 2021 11:46:14 +1000 Subject: [PATCH 05/10] Remove debug message --- InvenTree/InvenTree/version.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index 33a4aa3c0e..f302c84d6f 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -88,9 +88,6 @@ def isInvenTreeDevelopmentVersion(): """ Return True if current InvenTree version is a "development" version """ - - print("is dev?", inventreeVersion()) - return inventreeVersion().endswith('dev') From eb48c6ebdb48e64e98e1bf93283798e2128fd0f9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 Sep 2021 09:29:14 +1000 Subject: [PATCH 06/10] Delete app_issue.md --- .github/ISSUE_TEMPLATE/app_issue.md | 30 ----------------------------- 1 file changed, 30 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/app_issue.md diff --git a/.github/ISSUE_TEMPLATE/app_issue.md b/.github/ISSUE_TEMPLATE/app_issue.md deleted file mode 100644 index e71861394c..0000000000 --- a/.github/ISSUE_TEMPLATE/app_issue.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: App issue -about: Report a bug or issue with the InvenTree app -title: "[APP] Enter bug description" -labels: bug, app -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of the bug or issue - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to ... -2. Select ... -3. ... - -**Expected Behavior** -A clear and concise description of what you expected to happen - -**Screenshots** -If applicable, add screenshots to help explain your problem - -**Version Information** - -- App platform: *Select iOS or Android* -- App version: *Enter app version* -- Server version: *Enter server version* From 16e00962f5f5b46cc09910ff0be2a5a5ee4ebf1e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 Sep 2021 10:14:25 +1000 Subject: [PATCH 07/10] Override the "delete" behaviour for StockItem API - Mark for deletion instead of calling database delete - Returns (almost) instantly instead of hanging - Much better UI experience when performing bulk delete operations --- InvenTree/stock/api.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 017457f600..eaa65dd763 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -109,6 +109,17 @@ class StockDetail(generics.RetrieveUpdateDestroyAPIView): return super().update(request, *args, **kwargs) + def perform_destroy(self, instance): + """ + Instead of "deleting" the StockItem + (which may take a long time) + we instead schedule it for deletion at a later date. + + The background worker will delete these in the future + """ + + instance.mark_for_deletion() + class StockAdjust(APIView): """ From 2d9ca7c1b654062d804c7ddcda52b6ac08c09cf5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 Sep 2021 10:36:01 +1000 Subject: [PATCH 08/10] Do not rebuild the entire StockItem tree every time a single StockItem is deleted! --- InvenTree/stock/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 3344dec0eb..1372e63406 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -1650,9 +1650,6 @@ def before_delete_stock_item(sender, instance, using, **kwargs): child.parent = instance.parent child.save() - # Rebuild the MPTT tree - StockItem.objects.rebuild() - class StockItemAttachment(InvenTreeAttachment): """ From d9704f4123e1cbe5f840bd7964ec8eb12cd7854a Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 Sep 2021 10:41:03 +1000 Subject: [PATCH 09/10] Add unit test for deleting stock items via the API --- InvenTree/stock/test_api.py | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 619b4444d7..3b6facc9a6 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -18,6 +18,7 @@ from InvenTree.api_tester import InvenTreeAPITestCase from common.models import InvenTreeSetting from .models import StockItem, StockLocation +from .tasks import delete_old_stock_items class StockAPITestCase(InvenTreeAPITestCase): @@ -37,6 +38,7 @@ class StockAPITestCase(InvenTreeAPITestCase): 'stock.add', 'stock_location.change', 'stock_location.add', + 'stock.delete', ] def setUp(self): @@ -591,6 +593,61 @@ class StocktakeTest(StockAPITestCase): self.assertContains(response, 'Valid location must be specified', status_code=status.HTTP_400_BAD_REQUEST) +class StockItemDeletionTest(StockAPITestCase): + """ + Tests for stock item deletion via the API + """ + + def test_delete(self): + + # Check there are no stock items scheduled for deletion + self.assertEqual( + StockItem.objects.filter(scheduled_for_deletion=True).count(), + 0 + ) + + # Create and then delete a bunch of stock items + for idx in range(10): + + # Create new StockItem via the API + response = self.post( + reverse('api-stock-list'), + { + 'part': 1, + 'location': 1, + 'quantity': idx, + }, + expected_code=201 + ) + + pk = response.data['pk'] + + item = StockItem.objects.get(pk=pk) + + self.assertFalse(item.scheduled_for_deletion) + + url = reverse('api-stock-detail', kwargs={'pk': pk}) + + # Request deletion via the API + self.delete( + reverse('api-stock-detail', kwargs={'pk': pk}), + expected_code=204 + ) + + # There should be 100x StockItem objects marked for deletion + self.assertEqual( + StockItem.objects.filter(scheduled_for_deletion=True).count(), + 10 + ) + + # Perform the actual delete (will take some time) + delete_old_stock_items() + + self.assertEqual( + StockItem.objects.filter(scheduled_for_deletion=True).count(), + 0 + ) + class StockTestResultTest(StockAPITestCase): def get_url(self): From 62e62af5fc08cde8bd7b9102d6685c5a2194e80e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 28 Sep 2021 10:41:30 +1000 Subject: [PATCH 10/10] PEP style fixes --- InvenTree/stock/test_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/InvenTree/stock/test_api.py b/InvenTree/stock/test_api.py index 3b6facc9a6..21c355fae2 100644 --- a/InvenTree/stock/test_api.py +++ b/InvenTree/stock/test_api.py @@ -626,8 +626,6 @@ class StockItemDeletionTest(StockAPITestCase): self.assertFalse(item.scheduled_for_deletion) - url = reverse('api-stock-detail', kwargs={'pk': pk}) - # Request deletion via the API self.delete( reverse('api-stock-detail', kwargs={'pk': pk}), @@ -648,6 +646,7 @@ class StockItemDeletionTest(StockAPITestCase): 0 ) + class StockTestResultTest(StockAPITestCase): def get_url(self):