From 09d9529f0de1161f7807dc11e455ddc4fce22278 Mon Sep 17 00:00:00 2001 From: imperosol Date: Mon, 29 Sep 2025 14:20:44 +0200 Subject: [PATCH] fix: 500 on product create view --- club/views.py | 11 ++----- counter/forms.py | 21 ++++++++------ counter/tests/test_product.py | 54 +++++++++++++++++++++++++++++++++-- counter/views/admin.py | 6 ++-- eboutic/views.py | 4 +-- 5 files changed, 71 insertions(+), 25 deletions(-) diff --git a/club/views.py b/club/views.py index b10c4a09..b36e1b5b 100644 --- a/club/views.py +++ b/club/views.py @@ -29,11 +29,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import NON_FIELD_ERRORS, PermissionDenied, ValidationError from django.core.paginator import InvalidPage, Paginator from django.db.models import Sum -from django.http import ( - Http404, - HttpResponseRedirect, - StreamingHttpResponse, -) +from django.http import Http404, HttpResponseRedirect, StreamingHttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy from django.utils import timezone @@ -58,10 +54,7 @@ from com.views import ( PosterEditBaseView, PosterListBaseView, ) -from core.auth.mixins import ( - CanEditMixin, - CanViewMixin, -) +from core.auth.mixins import CanEditMixin, CanViewMixin from core.models import PageRev from core.views import DetailFormView, PageEditViewBase from core.views.mixins import TabedViewMixin diff --git a/counter/forms.py b/counter/forms.py index 3b1df846..990d4afe 100644 --- a/counter/forms.py +++ b/counter/forms.py @@ -232,13 +232,16 @@ class ScheduledProductActionForm(forms.ModelForm): class BaseScheduledProductActionFormSet(BaseModelFormSet): def __init__(self, *args, product: Product, **kwargs): - queryset = ( - product.scheduled_actions.filter( - enabled=True, clocked__clocked_time__gt=now() + if product.id: + queryset = ( + product.scheduled_actions.filter( + enabled=True, clocked__clocked_time__gt=now() + ) + .order_by("clocked__clocked_time") + .select_related("clocked") ) - .order_by("clocked__clocked_time") - .select_related("clocked") - ) + else: + queryset = ScheduledProductAction.objects.none() form_kwargs = {"product": product} super().__init__(*args, queryset=queryset, form_kwargs=form_kwargs, **kwargs) @@ -260,7 +263,7 @@ ScheduledProductActionFormSet = forms.modelformset_factory( ) -class ProductEditForm(forms.ModelForm): +class ProductForm(forms.ModelForm): error_css_class = "error" required_css_class = "required" @@ -367,7 +370,7 @@ class CloseCustomerAccountForm(forms.Form): ) -class ProductForm(forms.Form): +class BasketProductForm(forms.Form): quantity = forms.IntegerField(min_value=1, required=True) id = forms.IntegerField(min_value=0, required=True) @@ -472,5 +475,5 @@ class BaseBasketForm(forms.BaseFormSet): BasketForm = forms.formset_factory( - ProductForm, formset=BaseBasketForm, absolute_max=None, min_num=1 + BasketProductForm, formset=BaseBasketForm, absolute_max=None, min_num=1 ) diff --git a/counter/tests/test_product.py b/counter/tests/test_product.py index 8daab2b1..432178f3 100644 --- a/counter/tests/test_product.py +++ b/counter/tests/test_product.py @@ -6,14 +6,16 @@ import pytest from django.conf import settings from django.core.cache import cache from django.core.files.uploadedfile import SimpleUploadedFile -from django.test import Client +from django.test import Client, TestCase from django.urls import reverse from model_bakery import baker from PIL import Image -from pytest_django.asserts import assertNumQueries +from pytest_django.asserts import assertNumQueries, assertRedirects +from club.models import Club from core.baker_recipes import board_user, subscriber_user from core.models import Group, User +from counter.forms import ProductForm from counter.models import Product, ProductType @@ -84,3 +86,51 @@ def test_fetch_product_nb_queries(client: Client): # - 1 for the actual request # - 1 to prefetch the related buying_groups client.get(reverse("api:search_products_detailed")) + + +class TestCreateProduct(TestCase): + @classmethod + def setUpTestData(cls): + cls.product_type = baker.make(ProductType) + cls.club = baker.make(Club) + cls.data = { + "name": "foo", + "description": "bar", + "product_type": cls.product_type.id, + "club": cls.club.id, + "code": "FOO", + "purchase_price": 1.0, + "selling_price": 1.0, + "special_selling_price": 1.0, + "limit_age": 0, + "form-TOTAL_FORMS": 0, + "form-INITIAL_FORMS": 0, + } + + def test_form(self): + form = ProductForm(data=self.data) + print(form.errors) + assert form.is_valid() + instance = form.save() + assert instance.club == self.club + assert instance.product_type == self.product_type + assert instance.name == "foo" + assert instance.selling_price == 1.0 + + def test_view(self): + self.client.force_login( + baker.make( + User, + groups=[Group.objects.get(id=settings.SITH_GROUP_COUNTER_ADMIN_ID)], + ) + ) + url = reverse("counter:new_product") + response = self.client.get(url) + assert response.status_code == 200 + response = self.client.post(url, data=self.data) + print(response.text) + assertRedirects(response, reverse("counter:product_list")) + product = Product.objects.last() + assert product.name == "foo" + assert product.club == self.club + assert product.product_type == self.product_type diff --git a/counter/views/admin.py b/counter/views/admin.py index 7c1d4727..38cf8878 100644 --- a/counter/views/admin.py +++ b/counter/views/admin.py @@ -32,7 +32,7 @@ from core.utils import get_semester_code, get_start_of_semester from counter.forms import ( CloseCustomerAccountForm, CounterEditForm, - ProductEditForm, + ProductForm, ReturnableProductForm, ) from counter.models import ( @@ -146,7 +146,7 @@ class ProductCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView): """A create view for the admins.""" model = Product - form_class = ProductEditForm + form_class = ProductForm template_name = "counter/product_form.jinja" current_tab = "products" @@ -155,7 +155,7 @@ class ProductEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView): """An edit view for the admins.""" model = Product - form_class = ProductEditForm + form_class = ProductForm pk_url_kwarg = "product_id" template_name = "counter/product_form.jinja" current_tab = "products" diff --git a/eboutic/views.py b/eboutic/views.py index bf232621..d80f0238 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -48,7 +48,7 @@ from django_countries.fields import Country from core.auth.mixins import CanViewMixin from core.views.mixins import FragmentMixin, UseFragmentsMixin -from counter.forms import BaseBasketForm, BillingInfoForm, ProductForm +from counter.forms import BaseBasketForm, BillingInfoForm, BasketProductForm from counter.models import ( BillingInfo, Customer, @@ -78,7 +78,7 @@ class BaseEbouticBasketForm(BaseBasketForm): EbouticBasketForm = forms.formset_factory( - ProductForm, formset=BaseEbouticBasketForm, absolute_max=None, min_num=1 + BasketProductForm, formset=BaseEbouticBasketForm, absolute_max=None, min_num=1 )