From 106c238af5d452ea5071e42d13e2d524aae5aace Mon Sep 17 00:00:00 2001 From: simonkuehling Date: Wed, 8 Mar 2023 00:50:24 +0100 Subject: [PATCH] Add bulk delete for purchase order line items (#4452) * add bulk delete for purchase order line items * bump API version * fix JS style * handle parts with no linked manufacturer part correctly * add unit test for purchase order line item bulk delete --- InvenTree/InvenTree/api_version.py | 5 +- InvenTree/order/api.py | 2 +- .../order/purchase_order_detail.html | 16 ++++ InvenTree/order/test_api.py | 20 +++++ InvenTree/templates/js/translated/order.js | 80 +++++++++++++++++++ 5 files changed, 121 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index afcb7ea22e..7b003d9406 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 99 +INVENTREE_API_VERSION = 100 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v100 -> 2023-03-04 : https://github.com/inventree/InvenTree/pull/4452 + - Adds bulk delete of PurchaseOrderLineItems to API + v99 -> 2023-03-03 : https://github.com/inventree/InvenTree/pull/4445 - Adds sort by "responsible" to PurchaseOrderAPI diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index 83ca354df1..b4a77fa34d 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -495,7 +495,7 @@ class PurchaseOrderLineItemFilter(rest_filters.FilterSet): return queryset -class PurchaseOrderLineItemList(APIDownloadMixin, ListCreateAPI): +class PurchaseOrderLineItemList(APIDownloadMixin, ListCreateDestroyAPIView): """API endpoint for accessing a list of PurchaseOrderLineItem objects. - GET: Return a list of PurchaseOrder Line Item objects diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index 914c97d6ab..a7cceb0d8a 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -38,6 +38,22 @@
+ {% if roles.purchase_order.change %} + {% if order.is_pending or allow_extra_editing %} + + {% endif %} + {% endif %} + {% include "filter_list.html" with id="purchase-order-lines" %}
diff --git a/InvenTree/order/test_api.py b/InvenTree/order/test_api.py index f37937d7ce..976f198cad 100644 --- a/InvenTree/order/test_api.py +++ b/InvenTree/order/test_api.py @@ -603,6 +603,26 @@ class PurchaseOrderLineItemTest(OrderTest): self.filter({'has_pricing': 1}, 0) self.filter({'has_pricing': 0}, 5) + def test_po_line_bulk_delete(self): + """Test that we can bulk delete multiple PurchaseOrderLineItems via the API.""" + n = models.PurchaseOrderLineItem.objects.count() + + self.assignRole('purchase_order.delete') + + url = reverse('api-po-line-list') + + # Try to delete a set of line items via their IDs + self.delete( + url, + { + 'items': [1, 2], + }, + expected_code=204, + ) + + # We should have 2 less PurchaseOrderLineItems after deletign them + self.assertEqual(models.PurchaseOrderLineItem.objects.count(), n - 2) + class PurchaseOrderDownloadTest(OrderTest): """Unit tests for downloading PurchaseOrder data via the API endpoint.""" diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index 55b99f7d40..1ec8b48702 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -914,6 +914,7 @@ function poLineItemFields(options={}) { // Returned prices are in increasing order of quantity if (response.length > 0) { var idx = 0; + var index = 0; for (var idx = 0; idx < response.length; idx++) { if (response[idx].quantity > quantity) { @@ -2213,6 +2214,71 @@ function loadPurchaseOrderTable(table, options) { } +/* + * Delete the selected Purchase Order Line Items from the database + */ +function deletePurchaseOrderLineItems(items, options={}) { + + function renderItem(item, opts={}) { + + var part = item.part_detail; + var thumb = thumbnailImage(item.part_detail.thumbnail || item.part_detail.image); + var MPN = item.supplier_part_detail.manufacturer_part_detail ? item.supplier_part_detail.manufacturer_part_detail.MPN : '-'; + + var html = ` + + ${thumb} ${part.full_name} + ${part.description} + ${item.supplier_part_detail.SKU} + ${MPN} + ${item.quantity} + + `; + + return html; + } + + var rows = ''; + var ids = []; + + items.forEach(function(item) { + rows += renderItem(item); + ids.push(item.pk); + }); + + var html = ` +
+ {% trans "All selected Line items will be deleted" %} +
+ + + + + + + + + + ${rows} +
{% trans "Part" %}{% trans "Description" %}{% trans "SKU" %}{% trans "MPN" %}{% trans "Quantity" %}
+ `; + + constructForm('{% url "api-po-line-list" %}', { + method: 'DELETE', + multi_delete: true, + title: '{% trans "Delete selected Line items?" %}', + form_data: { + items: ids, + }, + preFormContent: html, + onSuccess: function() { + // Refresh the table once the line items are deleted + $('#po-line-table').bootstrapTable('refresh'); + }, + }); +} + + /** * Load a table displaying line items for a particular PurchasesOrder * @param {String} table - HTML ID tag e.g. '#table' @@ -2305,6 +2371,13 @@ function loadPurchaseOrderLineItemTable(table, options={}) { } }); }); + + // Callback for bulk deleting mutliple lines + $('#po-lines-bulk-delete').off('click').on('click', function() { + var rows = getTableData(' #po-line-table'); + + deletePurchaseOrderLineItems(rows); + }); } if (options.allow_receive) { @@ -2569,6 +2642,13 @@ function loadPurchaseOrderLineItemTable(table, options={}) { ] }); + linkButtonsToSelection( + table, + [ + '#multi-select-options', + ] + ); + }