From ea83d4b2904ffeeebf0982a89b325cec9d1208cd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 6 Jun 2022 21:27:19 +1000 Subject: [PATCH] Refactor stock item test result form for API (#3143) * Fix "polarity" of modal form submit button (cherry picked from commit 0e4550f28895af626715723e450792881f7fd882) * Use existing API functionality to delete all test results for a particular StockItem * Remove outdated forms / views --- InvenTree/InvenTree/forms.py | 54 +---------------------- InvenTree/InvenTree/urls.py | 4 +- InvenTree/InvenTree/views.py | 41 ++--------------- InvenTree/stock/templates/stock/item.html | 45 +++++++++++++++++-- InvenTree/stock/urls.py | 1 - InvenTree/stock/views.py | 38 ---------------- 6 files changed, 48 insertions(+), 135 deletions(-) diff --git a/InvenTree/InvenTree/forms.py b/InvenTree/InvenTree/forms.py index 7ee9c8634a..04e95120e4 100644 --- a/InvenTree/InvenTree/forms.py +++ b/InvenTree/InvenTree/forms.py @@ -16,13 +16,12 @@ from allauth.exceptions import ImmediateHttpResponse from allauth.socialaccount.adapter import DefaultSocialAccountAdapter from allauth_2fa.adapter import OTPAdapter from allauth_2fa.utils import user_has_valid_totp_device -from crispy_forms.bootstrap import (AppendedText, Div, PrependedAppendedText, - PrependedText, StrictButton) +from crispy_forms.bootstrap import (AppendedText, PrependedAppendedText, + PrependedText) from crispy_forms.helper import FormHelper from crispy_forms.layout import Field, Layout from common.models import InvenTreeSetting -from part.models import PartCategory logger = logging.getLogger('inventree') @@ -109,22 +108,6 @@ class HelperForm(forms.ModelForm): self.helper.layout = Layout(*layouts) -class ConfirmForm(forms.Form): - """Generic confirmation form.""" - - confirm = forms.BooleanField( - required=False, initial=False, - help_text=_("Confirm") - ) - - class Meta: - """Metaclass options.""" - - fields = [ - 'confirm' - ] - - class DeleteForm(forms.Form): """Generic deletion form which provides simple user confirmation.""" @@ -185,39 +168,6 @@ class SetPasswordForm(HelperForm): ] -class SettingCategorySelectForm(forms.ModelForm): - """Form for setting category settings.""" - - category = forms.ModelChoiceField(queryset=PartCategory.objects.all()) - - class Meta: - """Metaclass options.""" - - model = PartCategory - fields = [ - 'category' - ] - - def __init__(self, *args, **kwargs): - """Setup form layout.""" - super().__init__(*args, **kwargs) - - self.helper = FormHelper() - # Form rendering - self.helper.form_show_labels = False - self.helper.layout = Layout( - Div( - Div(Field('category'), - css_class='col-sm-6', - style='width: 70%;'), - Div(StrictButton(_('Select Category'), css_class='btn btn-primary', type='submit'), - css_class='col-sm-6', - style='width: 30%; padding-left: 0;'), - css_class='row', - ), - ) - - # override allauth class CustomSignupForm(SignupForm): """Override to use dynamic settings.""" diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index e1ac6ed1f3..897350e611 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -37,7 +37,7 @@ from .views import (AppearanceSelectView, CurrencyRefreshView, CustomSessionDeleteOtherView, CustomSessionDeleteView, DatabaseStatsView, DynamicJsView, EditUserView, IndexView, NotificationsView, SearchView, SetPasswordView, - SettingCategorySelectView, SettingsView, auth_request) + SettingsView, auth_request) admin.site.site_header = "InvenTree Admin" @@ -74,8 +74,6 @@ settings_urls = [ re_path(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'), re_path(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'), - re_path(r'^category/', SettingCategorySelectView.as_view(), name='settings-category'), - # Catch any other urls re_path(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'), ] diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index 2088d5bc20..cb5d1be51f 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -17,8 +17,8 @@ from django.urls import reverse_lazy from django.utils.timezone import now from django.utils.translation import gettext_lazy as _ from django.views import View -from django.views.generic import (CreateView, DeleteView, DetailView, FormView, - ListView, UpdateView) +from django.views.generic import (CreateView, DeleteView, DetailView, ListView, + UpdateView) from django.views.generic.base import RedirectView, TemplateView from allauth.account.forms import AddEmailForm @@ -34,8 +34,7 @@ from common.settings import currency_code_default, currency_codes from part.models import PartCategory from users.models import RuleSet, check_user_role -from .forms import (DeleteForm, EditUserForm, SetPasswordForm, - SettingCategorySelectForm) +from .forms import DeleteForm, EditUserForm, SetPasswordForm from .helpers import str2bool @@ -801,40 +800,6 @@ class AppearanceSelectView(RedirectView): return redirect(reverse_lazy('settings')) -class SettingCategorySelectView(FormView): - """View for selecting categories in settings.""" - - form_class = SettingCategorySelectForm - success_url = reverse_lazy('settings-category') - template_name = "InvenTree/settings/category.html" - - def get_initial(self): - """Set category selection.""" - initial = super().get_initial() - - category = self.request.GET.get('category', None) - if category: - initial['category'] = category - - return initial - - def post(self, request, *args, **kwargs): - """Handle POST request (which contains category selection). - - Pass the selected category to the page template - """ - form = self.get_form() - - if form.is_valid(): - context = self.get_context_data() - - context['category'] = form.cleaned_data['category'] - - return super(SettingCategorySelectView, self).render_to_response(context) - - return self.form_invalid(form) - - class DatabaseStatsView(AjaxView): """View for displaying database statistics.""" diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index d0822b8105..e951428378 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -265,10 +265,49 @@ {% if user.is_staff %} $("#delete-test-results").click(function() { - launchModalForm( - "{% url 'stock-item-delete-test-data' item.id %}", + + var url = '{% url "api-stock-test-result-list" %}'; + + inventreeGet( + url, { - success: reloadTable, + stock_item: {{ item.pk }}, + }, + { + success: function(response) { + + var results = []; + + // Ensure that we are only deleting the correct test results + response.forEach(function(item) { + if (item.stock_item == {{ item.pk }}) { + results.push(item); + } + }); + + var html = ` +
+ {% trans "Delete all test results for this stock item" %} +
`; + + constructFormBody({}, { + method: 'DELETE', + title: '{% trans "Delete Test Data" %}', + preFormContent: html, + onSubmit: function(fields, opts) { + inventreeMultiDelete( + url, + results, + { + modal: opts.modal, + success: function() { + reloadTable(); + } + } + ) + } + }); + } } ); }); diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 4ed2733181..f338116d72 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -20,7 +20,6 @@ stock_item_detail_urls = [ re_path(r'^convert/', views.StockItemConvert.as_view(), name='stock-item-convert'), re_path(r'^delete/', views.StockItemDelete.as_view(), name='stock-item-delete'), re_path(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'), - re_path(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'), # Anything else - direct to the item detail view re_path('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 5277aad990..b16fd640de 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -6,8 +6,6 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import DetailView, ListView import common.settings -from InvenTree.forms import ConfirmForm -from InvenTree.helpers import str2bool from InvenTree.views import (AjaxDeleteView, AjaxUpdateView, InvenTreeRoleMixin, QRCodeView) from plugin.views import InvenTreePluginViewMixin @@ -123,42 +121,6 @@ class StockLocationQRCode(QRCodeView): return None -class StockItemDeleteTestData(AjaxUpdateView): - """View for deleting all test data.""" - - model = StockItem - form_class = ConfirmForm - ajax_form_title = _("Delete All Test Data") - - role_required = ['stock.change', 'stock.delete'] - - def get_form(self): - """Require confirm.""" - return ConfirmForm() - - def post(self, request, *args, **kwargs): - """Delete test data.""" - valid = False - - stock_item = StockItem.objects.get(pk=self.kwargs['pk']) - form = self.get_form() - - confirm = str2bool(request.POST.get('confirm', False)) - - if confirm is not True: - form.add_error('confirm', _('Confirm test data deletion')) - form.add_error(None, _('Check the confirmation box')) - else: - stock_item.test_results.all().delete() - valid = True - - data = { - 'form_valid': valid, - } - - return self.renderJsonResponse(request, form, data) - - class StockItemQRCode(QRCodeView): """View for displaying a QR code for a StockItem object."""