Source code for shuup.admin.modules.categories.forms

# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.db.transaction import atomic
from django.utils.translation import ugettext_lazy as _

from shuup.admin.forms import ShuupAdminForm
from shuup.admin.forms.fields import Select2MultipleField
from shuup.admin.forms.widgets import QuickAddCategorySelect, TextEditorWidget
from shuup.admin.shop_provider import get_shop
from shuup.admin.utils.forms import filter_form_field_choices
from shuup.core.models import Category, CategoryStatus, Product, ShopProduct, ShopProductVisibility
from shuup.utils.django_compat import force_text


[docs]class CategoryBaseForm(ShuupAdminForm):
[docs] class Meta: model = Category fields = ( "parent", "status", "ordering", "visibility", "visible_in_menu", "visibility_groups", "name", "image", "description", "slug", ) widgets = { "status": forms.RadioSelect, "visibility": forms.RadioSelect, "description": TextEditorWidget(), "parent": QuickAddCategorySelect(editable_model="shuup.Category"), }
def __init__(self, request, **kwargs): self.request = request super(CategoryBaseForm, self).__init__(**kwargs) # Exclude `DELETED`. We don't want people to use that field to set a category as deleted. filter_form_field_choices(self.fields["status"], (CategoryStatus.DELETED.value,), invert=True) # Exclude current category from parents, because it cannot be its own child anyways category_queryset = Category.objects.filter(shops=get_shop(request)).exclude(status=CategoryStatus.DELETED) self.fields["parent"].queryset = category_queryset self.fields["parent"].choices = [(None, "----")] + [ (category.pk, force_text(category)) for category in category_queryset.exclude(id=kwargs["instance"].pk) ]
[docs] def clean_parent(self): parent = self.cleaned_data.get("parent") if parent and self.request.shop not in parent.shops.all(): raise ValidationError(_("Can't use this category as a parent for this shop."), code="invalid_parent") return parent
[docs] def save(self, commit=True): instance = super(CategoryBaseForm, self).save(commit) instance.shops.add(self.request.shop)
[docs]class CategoryProductForm(forms.Form): primary_products = Select2MultipleField( label=_("Primary Category"), help_text=_("Set this category as a primary category for selected products."), model=Product, required=False, ) additional_products = Select2MultipleField( label=_("Additional Category"), help_text=_("Add selected products to this category."), model=Product, required=False, ) remove_products = forms.MultipleChoiceField( label=_("Remove Products"), help_text=_("Remove selected products from this category."), required=False ) def __init__(self, shop, category, **kwargs): self.shop = shop self.category = category super(CategoryProductForm, self).__init__(**kwargs) self.fields["remove_products"].choices = [(None, "-----")] + [ (obj.product.pk, obj.product.name) for obj in category.shop_products.filter(shop=shop) ] @atomic
[docs] def save(self): data = self.cleaned_data is_visible = self.category.status == CategoryStatus.VISIBLE visibility_groups = self.category.visibility_groups.all() primary_product_ids = [int(product_id) for product_id in data.get("primary_products", [])] for shop_product in ShopProduct.objects.filter( Q(shop_id=self.shop.id), Q(product_id__in=primary_product_ids) | Q(product__variation_parent_id__in=primary_product_ids), ): shop_product.primary_category = self.category shop_product.visibility = ( ShopProductVisibility.ALWAYS_VISIBLE if is_visible else ShopProductVisibility.NOT_VISIBLE ) shop_product.visibility_limit = self.category.visibility.value shop_product.visibility_groups.set(visibility_groups) shop_product.save() shop_product.categories.add(self.category) additional_product_ids = [int(product_id) for product_id in data.get("additional_products", [])] for shop_product in ShopProduct.objects.filter( Q(shop_id=self.shop.id), Q(product_id__in=additional_product_ids) | Q(product__variation_parent_id__in=additional_product_ids), ): shop_product.categories.add(self.category) remove_product_ids = [int(product_id) for product_id in data.get("remove_products", [])] for shop_product in ShopProduct.objects.filter( Q(product_id__in=remove_product_ids) | Q(product__variation_parent_id__in=remove_product_ids) ): if shop_product.primary_category == self.category: if self.category in shop_product.categories.all(): shop_product.categories.remove(self.category) shop_product.primary_category = None shop_product.save() shop_product.categories.remove(self.category)