Allow build orders to be deleted via the API (#3155)

This commit is contained in:
Oliver 2022-06-08 07:45:42 +10:00 committed by GitHub
parent 403655e3d2
commit a816c14b95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 27 deletions

View File

@ -1,8 +1,10 @@
"""JSON API for the Build app."""
from django.urls import include, re_path
from django.utils.translation import gettext_lazy as _
from rest_framework import filters, generics
from rest_framework.exceptions import ValidationError
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import rest_framework as rest_filters
@ -198,12 +200,24 @@ class BuildList(APIDownloadMixin, generics.ListCreateAPIView):
return self.serializer_class(*args, **kwargs)
class BuildDetail(generics.RetrieveUpdateAPIView):
class BuildDetail(generics.RetrieveUpdateDestroyAPIView):
"""API endpoint for detail view of a Build object."""
queryset = Build.objects.all()
serializer_class = build.serializers.BuildSerializer
def destroy(self, request, *args, **kwargs):
"""Only allow deletion of a BuildOrder if the build status is CANCELLED"""
build = self.get_object()
if build.status != BuildStatus.CANCELLED:
raise ValidationError({
"non_field_errors": [_("Build must be cancelled before it can be deleted")]
})
return super().destroy(request, *args, **kwargs)
class BuildUnallocate(generics.CreateAPIView):
"""API endpoint for unallocating stock items from a build order.

View File

@ -249,9 +249,11 @@ src="{% static 'img/blank_image.png' %}"
{% endif %}
$("#build-delete").on('click', function() {
launchModalForm(
"{% url 'build-delete' build.id %}",
constructForm(
'{% url "api-build-detail" build.pk %}',
{
method: 'DELETE',
title: '{% trans "Delete Build Order" %}',
redirect: "{% url 'build-index' %}",
}
);

View File

@ -1,7 +0,0 @@
{% extends "modal_delete_form.html" %}
{% load i18n %}
{% block pre_form_content %}
{% trans "Are you sure you want to delete this build?" %}
{% endblock %}

View File

@ -90,7 +90,7 @@ class BuildAPITest(InvenTreeAPITestCase):
# Required roles to access Build API endpoints
roles = [
'build.change',
'build.add'
'build.add',
]
@ -268,6 +268,39 @@ class BuildTest(BuildAPITest):
self.assertEqual(bo.status, BuildStatus.CANCELLED)
def test_delete(self):
"""Test that we can delete a BuildOrder via the API"""
bo = Build.objects.get(pk=1)
url = reverse('api-build-detail', kwargs={'pk': bo.pk})
# At first we do not have the required permissions
self.delete(
url,
expected_code=403,
)
self.assignRole('build.delete')
# As build is currently not 'cancelled', it cannot be deleted
self.delete(
url,
expected_code=400,
)
bo.status = BuildStatus.CANCELLED
bo.save()
# Now, we should be able to delete
self.delete(
url,
expected_code=204,
)
with self.assertRaises(Build.DoesNotExist):
Build.objects.get(pk=1)
def test_create_delete_output(self):
"""Test that we can create and delete build outputs via the API."""
bo = Build.objects.get(pk=1)

View File

@ -4,15 +4,12 @@ from django.urls import include, re_path
from . import views
build_detail_urls = [
re_path(r'^delete/', views.BuildDelete.as_view(), name='build-delete'),
re_path(r'^.*$', views.BuildDetail.as_view(), name='build-detail'),
]
build_urls = [
re_path(r'^(?P<pk>\d+)/', include(build_detail_urls)),
re_path(r'^(?P<pk>\d+)/', include([
re_path(r'^.*$', views.BuildDetail.as_view(), name='build-detail'),
])),
re_path(r'.*$', views.BuildIndex.as_view(), name='build-index'),
]

View File

@ -1,11 +1,9 @@
"""Django views for interacting with Build objects."""
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from .models import Build
from InvenTree.views import AjaxDeleteView
from InvenTree.views import InvenTreeRoleMixin
from InvenTree.status_codes import BuildStatus
@ -49,11 +47,3 @@ class BuildDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
ctx['has_untracked_bom_items'] = build.has_untracked_bom_items()
return ctx
class BuildDelete(AjaxDeleteView):
"""View to delete a build."""
model = Build
ajax_template_name = 'build/delete_build.html'
ajax_form_title = _('Delete Build Order')