mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-01 03:00:54 +00:00
Adds API mixin for "bulk delete" (#3146)
* Introduces a BulkDelete API mixin class - Allows deletion of multiple items against a single API request * Bump API version * Adds BulkDelete mixin to StockItemTestResult API class * refactor "multi BOM Item delete" to use new approach * Refactor various attachment API endpoints * Refactor multi delete for StockItem * Convert remaining enndpoints over * Fix for API test code
This commit is contained in:
@ -22,7 +22,8 @@ import stock.serializers as StockSerializers
|
||||
from build.models import Build
|
||||
from company.models import Company, SupplierPart
|
||||
from company.serializers import CompanySerializer, SupplierPartSerializer
|
||||
from InvenTree.api import APIDownloadMixin, AttachmentMixin
|
||||
from InvenTree.api import (APIDownloadMixin, AttachmentMixin,
|
||||
ListCreateDestroyAPIView)
|
||||
from InvenTree.filters import InvenTreeOrderingFilter
|
||||
from InvenTree.helpers import (DownloadFile, extract_serial_numbers, isNull,
|
||||
str2bool)
|
||||
@ -465,7 +466,7 @@ class StockFilter(rest_filters.FilterSet):
|
||||
updated_after = rest_filters.DateFilter(label='Updated after', field_name='updated', lookup_expr='gte')
|
||||
|
||||
|
||||
class StockList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
class StockList(APIDownloadMixin, ListCreateDestroyAPIView):
|
||||
"""API endpoint for list view of Stock objects.
|
||||
|
||||
- GET: Return a list of all StockItem objects (with optional query filters)
|
||||
@ -1043,7 +1044,7 @@ class StockList(APIDownloadMixin, generics.ListCreateAPIView):
|
||||
]
|
||||
|
||||
|
||||
class StockAttachmentList(AttachmentMixin, generics.ListCreateAPIView):
|
||||
class StockAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||
"""API endpoint for listing (and creating) a StockItemAttachment (file upload)."""
|
||||
|
||||
queryset = StockItemAttachment.objects.all()
|
||||
@ -1074,7 +1075,7 @@ class StockItemTestResultDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
serializer_class = StockSerializers.StockItemTestResultSerializer
|
||||
|
||||
|
||||
class StockItemTestResultList(generics.ListCreateAPIView):
|
||||
class StockItemTestResultList(ListCreateDestroyAPIView):
|
||||
"""API endpoint for listing (and creating) a StockItemTestResult object."""
|
||||
|
||||
queryset = StockItemTestResult.objects.all()
|
||||
|
@ -276,12 +276,12 @@
|
||||
{
|
||||
success: function(response) {
|
||||
|
||||
var results = [];
|
||||
var items = [];
|
||||
|
||||
// Ensure that we are only deleting the correct test results
|
||||
response.forEach(function(item) {
|
||||
if (item.stock_item == {{ item.pk }}) {
|
||||
results.push(item);
|
||||
response.forEach(function(result) {
|
||||
if (result.stock_item == {{ item.pk }}) {
|
||||
items.push(result.pk);
|
||||
}
|
||||
});
|
||||
|
||||
@ -290,22 +290,14 @@
|
||||
{% trans "Delete all test results for this stock item" %}
|
||||
</div>`;
|
||||
|
||||
constructFormBody({}, {
|
||||
constructForm(url, {
|
||||
form_data: {
|
||||
items: items,
|
||||
},
|
||||
method: 'DELETE',
|
||||
title: '{% trans "Delete Test Data" %}',
|
||||
preFormContent: html,
|
||||
onSubmit: function(fields, opts) {
|
||||
inventreeMultiDelete(
|
||||
url,
|
||||
results,
|
||||
{
|
||||
modal: opts.modal,
|
||||
success: function() {
|
||||
reloadTable();
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
onSuccess: reloadTable,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import part.models
|
||||
from common.models import InvenTreeSetting
|
||||
from InvenTree.api_tester import InvenTreeAPITestCase
|
||||
from InvenTree.status_codes import StockStatus
|
||||
from stock.models import StockItem, StockLocation
|
||||
from stock.models import StockItem, StockItemTestResult, StockLocation
|
||||
|
||||
|
||||
class StockAPITestCase(InvenTreeAPITestCase):
|
||||
@ -934,6 +934,50 @@ class StockTestResultTest(StockAPITestCase):
|
||||
# Check that an attachment has been uploaded
|
||||
self.assertIsNotNone(response.data['attachment'])
|
||||
|
||||
def test_bulk_delete(self):
|
||||
"""Test that the BulkDelete endpoint works for this model"""
|
||||
|
||||
n = StockItemTestResult.objects.count()
|
||||
|
||||
tests = []
|
||||
|
||||
url = reverse('api-stock-test-result-list')
|
||||
|
||||
# Create some objects (via the API)
|
||||
for _ii in range(50):
|
||||
response = self.post(
|
||||
url,
|
||||
{
|
||||
'stock_item': 1,
|
||||
'test': f"Some test {_ii}",
|
||||
'result': True,
|
||||
'value': 'Test result value'
|
||||
},
|
||||
expected_code=201
|
||||
)
|
||||
|
||||
tests.append(response.data['pk'])
|
||||
|
||||
self.assertEqual(StockItemTestResult.objects.count(), n + 50)
|
||||
|
||||
# Attempt a delete without providing items
|
||||
self.delete(
|
||||
url,
|
||||
{},
|
||||
expected_code=400,
|
||||
)
|
||||
|
||||
# Now, let's delete all the newly created items with a single API request
|
||||
response = self.delete(
|
||||
url,
|
||||
{
|
||||
'items': tests,
|
||||
},
|
||||
expected_code=204
|
||||
)
|
||||
|
||||
self.assertEqual(StockItemTestResult.objects.count(), n)
|
||||
|
||||
|
||||
class StockAssignTest(StockAPITestCase):
|
||||
"""Unit tests for the stock assignment API endpoint, where stock items are manually assigned to a customer."""
|
||||
|
Reference in New Issue
Block a user