diff --git a/artel/store/forms.py b/artel/store/forms.py index 6822fe2..e687bc7 100644 --- a/artel/store/forms.py +++ b/artel/store/forms.py @@ -2,9 +2,9 @@ from django import forms from phonenumber_field.formfields import PhoneNumberField from store.models import ( + ProductTemplate, ProductCategoryParamValue, - ProductCategoryParam, - ProductCategory + Product ) @@ -40,39 +40,27 @@ class CustomerDataForm(forms.Form): ) -class ProductCategoryParamFormset(forms.BaseModelFormSet): - ... +class ButtonToggleSelect(forms.RadioSelect): + template_name = "store/forms/button_toggle_select.html" -class ProductCategoryParamValueForm(forms.ModelForm): - class Meta: - model = ProductCategoryParamValue - fields = ("key", "value") +class ProductTemplateConfigForm(forms.Form): - key = forms.CharField(required=True) - value = forms.ModelChoiceField( - queryset=ProductCategoryParamValue.objects.none(), - widget=forms.RadioSelect(attrs={"class": "btn-check", "type": "radio", "autocomplete": "off"}), - required=True - ) - - def _get_instace(self, key: str): - return ProductCategoryParam.objects.get(key=key) - - def __init__(self, *args, **kwargs): + def _create_dynamic_fields(self, template: ProductTemplate): + category_params = template.category.category_params.all() + for param in category_params: + self.fields[param.key] = forms.ModelChoiceField( + queryset=ProductCategoryParamValue.objects.filter(param=param), + widget=ButtonToggleSelect(attrs={"class": "btn-group btn-group-toggle"}), + ) + + def __init__( + self, template: ProductTemplate, *args, **kwargs + ): + self.template = template super().__init__(*args, **kwargs) - key = self.initial.get("key") - if not key: - return - self.cat_param = self._get_instace(key) - self.fields["value"].choices = [ - (param_value.pk, param_value.value) for param_value in self.cat_param.param_values.all() - ] + self._create_dynamic_fields(template) - def save(self, *args, **kwargs): - param_value = ProductCategoryParamValue.objects.get( - param__key=str(self.cleaned_data["key"]), - value=str(self.cleaned_data["value"]) - ) - print(param_value or "DUPSKo") - return param_value + def get_product(self): + params = list(self.cleaned_data.values()) + return Product.objects.get_or_create_by_params(template=self.template, params=params) diff --git a/artel/store/models.py b/artel/store/models.py index 01c7460..eb85f28 100644 --- a/artel/store/models.py +++ b/artel/store/models.py @@ -172,8 +172,7 @@ class ProductManager(models.Manager): def get_or_create_by_params(self, params: list[ProductCategoryParamValue], template: ProductTemplate): products = self.filter(template=template) - # TODO - other price - price_proposal = products.first().price if products.first() else 4.0 + for param in params: products = products.filter(params__pk=param.pk) @@ -186,7 +185,7 @@ class ProductManager(models.Manager): product = self.create( name=f"{template.title} - AUTOGENERATED", template=template, - price=price_proposal, + price=0, available=False ) for param in params: @@ -220,6 +219,8 @@ class Product(ClusterableModel): try: return self.product_images.get(is_main=True) except ProductImage.DoesNotExist: + if main_image := self.template.main_image: + return main_image return self.product_images.first() diff --git a/artel/store/templates/store/configure_product.html b/artel/store/templates/store/configure_product.html index b67a744..4e59610 100644 --- a/artel/store/templates/store/configure_product.html +++ b/artel/store/templates/store/configure_product.html @@ -23,21 +23,11 @@
{% csrf_token %} - - {{ formset.management_form }}
- {% for form in formset.forms %} + {% for field in form %}
-

{{form.cat_param}}

- {% if form.value.field.choices %} - - {% for value, label in form.value.field.choices %} -
- - -
- {% endfor %} - {% endif %} +

{{field.label}}

+ {{field}}
{% if forloop.counter|divisibleby:"2" %}
{% endif %} {% endfor %} diff --git a/artel/store/templates/store/configure_product_summary.html b/artel/store/templates/store/configure_product_summary.html index e69de29..59e9b4d 100644 --- a/artel/store/templates/store/configure_product_summary.html +++ b/artel/store/templates/store/configure_product_summary.html @@ -0,0 +1,52 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+
+
+ Responsive image +
+
+
+
+ {% for value in params_values %} +
+
+

{{value}}

+
+
+
+ {% endfor %} +
+
+
+
+ {% if not variant.available %} +
+
+ Niestety skonfigurowany przez Ciebie wariant produktu nie jest jeszcze dostępny. + Jeżeli jesteś zainteresowany tą konfiguracją złóż zapytanie ofertowe. +
+
+ {% endif %} +
+
+ {% if variant.available %} +

Cena: {{variant.price}} zł

+ {% endif %} +
+
+ Wróć do konfiguratora + {% if variant.available %} + + {% else %} + + {% endif %} +
+
+
+
+ +{% endblock %} diff --git a/artel/store/templates/store/forms/button_toggle_select.html b/artel/store/templates/store/forms/button_toggle_select.html new file mode 100644 index 0000000..2d5e4b6 --- /dev/null +++ b/artel/store/templates/store/forms/button_toggle_select.html @@ -0,0 +1,28 @@ + +{% with id=widget.attrs.id %} +
+ {% for group, options, index in widget.optgroups %} + {% for option in options %} + + + {% endfor %} + {% endfor %} +
+{% endwith %} + diff --git a/artel/store/tests/test_models.py b/artel/store/tests/test_models.py index b29364a..8e0e44b 100644 --- a/artel/store/tests/test_models.py +++ b/artel/store/tests/test_models.py @@ -138,7 +138,7 @@ class ProductTestCase(TestCase): ) self.assertIsNotNone(prod) self.assertFalse(prod.available) - self.assertEqual(prod.price, 4.0) + self.assertEqual(prod.price, 0) class OrderProductTestCase(TestCase): diff --git a/artel/store/tests/test_views.py b/artel/store/tests/test_views.py new file mode 100644 index 0000000..d5249a2 --- /dev/null +++ b/artel/store/tests/test_views.py @@ -0,0 +1,11 @@ +from django.test import TestCase + + +class ConfigureProductViewTestCase(TestCase): + + def setUp(self): + ... + + def test_sdkfsdf(self): + ... + diff --git a/artel/store/urls.py b/artel/store/urls.py index d49b1c7..7e181a9 100644 --- a/artel/store/urls.py +++ b/artel/store/urls.py @@ -10,7 +10,7 @@ router.register("cart-action", store_views.CartActionView, "cart-action") urlpatterns = [ path('product-configure//', store_views.ConfigureProductView.as_view(), name='product-configure'), - path('product-configure/summary//', store_views.ConfigureProductSummaryView.as_view(), name='product-configure-summary'), + path('product-configure/summary//', store_views.ConfigureProductSummaryView.as_view(), name='configure-product-summary'), path('cart/', store_views.CartView.as_view(), name='cart'), path("order/", store_views.OrderView.as_view(), name="order"), path("order/confirm/", store_views.OrderConfirmView.as_view(), name="order-confirm") diff --git a/artel/store/views.py b/artel/store/views.py index 75ff0dd..c499d15 100644 --- a/artel/store/views.py +++ b/artel/store/views.py @@ -20,8 +20,7 @@ from store.serializers import ( ) from store.forms import ( CustomerDataForm, - ProductCategoryParamValueForm, - ProductCategoryParamFormset + ProductTemplateConfigForm ) from store.models import ( Order, @@ -98,18 +97,11 @@ class ConfigureProductView(View): def get_context_data(self, pk: int, **kwargs: Any) -> Dict[str, Any]: template = ProductTemplate.objects.get(pk=pk) - category_params = template.category.category_params.all() - formset_class = modelformset_factory( - ProductCategoryParamValue, - form=ProductCategoryParamValueForm, - formset=ProductCategoryParamFormset - ) - formset = formset_class(queryset=category_params) + form = ProductTemplateConfigForm(template=template) context = { "template": template, "available_variants": Product.objects.filter(template__pk=pk), - "category_params": category_params, - "formset": formset + "form": form } return context @@ -121,41 +113,14 @@ class ConfigureProductView(View): def post(self, request, pk: int, *args, **kwargs): # first select template template = ProductTemplate.objects.get(pk=pk) - category_params = template.category.category_params.all() - params_values = [] - formset_class = modelformset_factory( - ProductCategoryParamValue, - form=ProductCategoryParamValueForm, - formset=ProductCategoryParamFormset - ) - formset = formset_class(queryset=category_params, data=request.POST) - print(request.POST) - if not formset.is_valid(): - print(formset.errors) - messages.error(request, "Niepoprawne dane") + form = ProductTemplateConfigForm(template=template, data=request.POST) + if not form.is_valid(): context = self.get_context_data(pk) - context["formset"] = formset + context["form"] = form return render(request, self.template_name, context) - - for form in formset.forms: - if not form.is_valid(): - messages.error(request, "Niepoprawne dane") - context = self.get_context_data(pk) - context["formset"] = formset - return render(request, self.template_name, context) - params_values.append(form.save()) - product_variant = Product.objects.get_or_create_by_params( - template=ProductTemplate.objects.get(pk=pk), params=params_values - ) - if not product_variant: - messages.error(request, "Nie udało się utworzyć wariantu produktu") - return HttpResponseRedirect(reverse("product-configure", kwargs={"pk": pk})) - - return HttpResponseRedirect( - reverse("product-configure-summary", kwargs={"variant_pk": product_variant.pk}) - ) - + product_variant = form.get_product() + return HttpResponseRedirect(reverse("configure-product-summary", args=[product_variant.pk])) class ConfigureProductSummaryView(View): template_name = "store/configure_product_summary.html"