from contextlib import suppress from typing import ClassVar, Type from constance.admin import Config from constance.admin import ConstanceAdmin as BaseConstanceAdmin from django.apps import apps from django.contrib.admin import ModelAdmin, TabularInline, action, register, site from django.contrib.gis.admin import GISModelAdmin from django.db.models import Model from django.utils.translation import gettext_lazy as _ from modeltranslation.translator import NotRegistered, translator from modeltranslation.utils import get_translation_fields from mptt.admin import DraggableMPTTAdmin from core.forms import OrderForm, OrderProductForm, VendorForm from core.models import ( Address, Attribute, AttributeGroup, AttributeValue, Brand, Category, CategoryTag, Feedback, Order, OrderProduct, Product, ProductImage, ProductTag, PromoCode, Promotion, Stock, Vendor, Wishlist, ) from evibes.settings import CONSTANCE_CONFIG class FieldsetsMixin: general_fields: list = [] relation_fields: list = [] model: ClassVar[Type[Model]] def get_fieldsets(self, request, obj=None): if request: pass if obj: pass fieldsets = [] def add_translations_fieldset(fss): with suppress(NotRegistered): transoptions = translator.get_options_for_model(self.model) translation_fields = [] for orig in transoptions.local_fields: translation_fields += get_translation_fields(orig) if translation_fields: fss = list(fss) + [(_("translations"), {"fields": translation_fields})] return fss if self.general_fields: fieldsets.append((_("general"), {"fields": self.general_fields})) if self.relation_fields: fieldsets.append((_("relations"), {"fields": self.relation_fields})) opts = self.model._meta if any(f.name == "uuid" for f in opts.fields): if any(f.name == "slug" for f in opts.fields): fieldsets.append((_("metadata"), {"fields": ["uuid", "slug"]})) else: fieldsets.append((_("metadata"), {"fields": ["uuid"]})) ts = [] for name in ("created", "modified"): if any(f.name == name for f in opts.fields): ts.append(name) if ts: fieldsets.append((_("timestamps"), {"fields": ts, "classes": ["collapse"]})) fieldsets = add_translations_fieldset(fieldsets) return fieldsets class ActivationActionsMixin: @action(description=str(_("activate selected %(verbose_name_plural)s"))) def activate_selected(self, request, queryset, **kwargs) -> str: if kwargs: pass if request: pass queryset.update(is_active=True) return str(_("%(verbose_name_plural)s activated successfully!")) @action(description=str(_("deactivate selected %(verbose_name_plural)s"))) def deactivate_selected(self, request, queryset, **kwargs) -> str: if kwargs: pass if request: pass queryset.update(is_active=False) return str(_("%(verbose_name_plural)s deactivated successfully.")) def get_actions(self, request, **kwargs): if kwargs: pass actions = super().get_actions(request) actions["activate_selected"] = ( self.activate_selected, "activate_selected", str(_("activate selected %(verbose_name_plural)s")), ) actions["deactivate_selected"] = ( self.deactivate_selected, "deactivate_selected", str(_("deactivate selected %(verbose_name_plural)s")), ) return actions class AttributeValueInline(TabularInline): model = AttributeValue extra = 0 autocomplete_fields = ["attribute"] is_navtab = True verbose_name = _("attribute value") verbose_name_plural = _("attribute values") icon = "fa-solid fa-list-ul" class ProductImageInline(TabularInline): model = ProductImage extra = 0 is_navtab = True verbose_name = _("image") verbose_name_plural = _("images") icon = "fa-regular fa-images" class StockInline(TabularInline): model = Stock extra = 0 is_navtab = True verbose_name = _("stock") verbose_name_plural = _("stocks") icon = "fa-solid fa-boxes-stacked" class OrderProductInline(TabularInline): model = OrderProduct extra = 0 readonly_fields = ("product", "quantity", "buy_price") form = OrderProductForm is_navtab = True verbose_name = _("order product") verbose_name_plural = _("order products") icon = "fa-solid fa-boxes-packing" def get_queryset(self, request): return super().get_queryset(request).select_related("product").only("product__name") class CategoryChildrenInline(TabularInline): model = Category fk_name = "parent" extra = 0 fields = ("name", "description", "is_active", "image", "markup_percent") is_navtab = True verbose_name = _("children") verbose_name_plural = _("children") icon = "fa-solid fa-leaf" @register(AttributeGroup) class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = AttributeGroup list_display = ("name", "modified") search_fields = ("uuid", "name") readonly_fields = ("uuid", "modified", "created") general_fields = ["is_active", "name", "parent"] relation_fields = [] @register(Attribute) class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Attribute list_display = ("name", "group", "value_type", "modified") list_filter = ("value_type", "group", "is_active") search_fields = ("uuid", "name", "group__name") readonly_fields = ("uuid", "modified", "created") autocomplete_fields = ["categories", "group"] general_fields = ["is_active", "name", "value_type"] relation_fields = ["group", "categories"] @register(AttributeValue) class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = AttributeValue list_display = ("attribute", "value", "modified") list_filter = ("attribute__group", "is_active") search_fields = ("uuid", "value", "attribute__name") readonly_fields = ("uuid", "modified", "created") autocomplete_fields = ["attribute"] general_fields = ["is_active", "value"] relation_fields = ["attribute", "product"] @register(Category) class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin): model = Category list_display = ("indented_title", "parent", "is_active", "modified") # noinspection PyUnresolvedReferences list_filter = ("is_active", "level", "created", "modified") search_fields = ("uuid", "name") inlines = [CategoryChildrenInline] autocomplete_fields = ["parent", "tags"] readonly_fields = ("slug", "uuid", "modified", "created") general_fields = ["is_active", "name", "description", "image", "markup_percent", "priority"] relation_fields = ["parent", "tags"] @register(Brand) class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Brand list_display = ("name",) list_filter = ("categories", "is_active") search_fields = ("uuid", "name", "categories__name") readonly_fields = ("uuid", "slug", "modified", "created") general_fields = ["is_active", "name", "description", "priority"] relation_fields = ["small_logo", "big_logo", "categories"] @register(Product) class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Product list_display = ( "name", "partnumber", "is_active", "category", "brand", "price", "rating", "modified", ) list_filter = ( "is_active", "is_digital", "stocks__vendor", "tags__name", "created", "modified", ) search_fields = ( "name", "partnumber", "brand__name", "brand__slug", "category__name", "category__slug", "uuid", "slug", ) readonly_fields = ("slug", "uuid", "modified", "created") autocomplete_fields = ("category", "brand", "tags") inlines = [AttributeValueInline, ProductImageInline, StockInline] general_fields = ["is_active", "name", "partnumber", "is_digital"] relation_fields = ["category", "brand", "tags"] @register(ProductTag) class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = ProductTag list_display = ("tag_name",) search_fields = ("tag_name",) readonly_fields = ("uuid", "modified", "created") general_fields = ["is_active", "tag_name", "name"] relation_fields = [] @register(CategoryTag) class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = CategoryTag list_display = ("tag_name",) search_fields = ("tag_name",) readonly_fields = ("uuid", "modified", "created") general_fields = ["is_active", "tag_name", "name"] relation_fields = [] @register(Vendor) class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Vendor list_display = ("name", "markup_percent", "modified") list_filter = ("markup_percent", "is_active") search_fields = ("name",) readonly_fields = ("uuid", "modified", "created") form = VendorForm general_fields = ["is_active", "name", "markup_percent", "authentication"] relation_fields = [] @register(Feedback) class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Feedback list_display = ("order_product", "rating", "comment", "modified") list_filter = ("rating", "is_active") search_fields = ("order_product__product__name", "comment") readonly_fields = ("uuid", "modified", "created") general_fields = ["is_active", "rating", "comment"] relation_fields = ["order_product"] @register(Order) class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Order list_display = ( "human_readable_id", "user", "status", "total_price", "buy_time", "modified", ) list_filter = ("status", "buy_time", "modified", "created") search_fields = ("user__email", "status", "uuid", "human_readable_id") readonly_fields = ( "total_price", "total_quantity", "human_readable_id", "uuid", "modified", "created", ) inlines = [OrderProductInline] form = OrderForm general_fields = ["is_active", "user", "status"] relation_fields = ["promo_code", "billing_address", "shipping_address"] @register(OrderProduct) class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = OrderProduct list_display = ("order", "product", "quantity", "buy_price", "status", "modified") list_filter = ("status",) search_fields = ("order__user__email", "product__name") readonly_fields = ("uuid", "modified", "created") form = OrderProductForm general_fields = ["is_active", "quantity", "buy_price", "status"] relation_fields = ["order", "product"] @register(PromoCode) class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = PromoCode list_display = ( "code", "discount_percent", "discount_amount", "start_time", "end_time", "used_on", ) list_filter = ("discount_percent", "discount_amount", "start_time", "end_time") search_fields = ("code",) readonly_fields = ("used_on", "uuid", "modified", "created") autocomplete_fields = ("user",) general_fields = [ "is_active", "code", "discount_amount", "discount_percent", "start_time", "end_time", "used_on", ] relation_fields = ["user"] @register(Promotion) class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Promotion list_display = ("name", "discount_percent", "modified") search_fields = ("name",) readonly_fields = ("uuid", "modified", "created") autocomplete_fields = ("products",) general_fields = ["is_active", "name", "discount_percent", "description"] relation_fields = ["products"] @register(Stock) class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Stock list_display = ("product", "vendor", "sku", "quantity", "price", "modified") list_filter = ("vendor", "quantity") search_fields = ("product__name", "vendor__name", "sku") readonly_fields = ("uuid", "modified", "created") autocomplete_fields = ("product", "vendor") general_fields = [ "is_active", "sku", "quantity", "price", "purchase_price", "digital_asset", ] relation_fields = ["product", "vendor"] @register(Wishlist) class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = Wishlist list_display = ("user", "modified") search_fields = ("user__email",) readonly_fields = ("uuid", "modified", "created") general_fields = ["is_active", "user"] relation_fields = ["products"] @register(ProductImage) class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): model = ProductImage list_display = ("alt", "product", "priority", "modified") list_filter = ("priority",) search_fields = ("alt", "product__name") readonly_fields = ("uuid", "modified", "created") autocomplete_fields = ("product",) general_fields = ["is_active", "alt", "priority", "image"] relation_fields = ["product"] @register(Address) class AddressAdmin(FieldsetsMixin, GISModelAdmin): model = Address list_display = ("street", "city", "region", "country", "user") list_filter = ("country", "region") search_fields = ("street", "city", "postal_code", "user__email") readonly_fields = ("uuid", "modified", "created") gis_widget_kwargs = { "attrs": { "default_lon": 37.61556, "default_lat": 55.75222, "default_zoom": 6, } } general_fields = [ "is_active", "address_line", "street", "district", "city", "region", "postal_code", "country", "raw_data", ] relation_fields = ["user", "api_response"] # Constance configuration class ConstanceConfig: class Meta: app_label = "core" object_name = "Config" concrete_model = None model_name = module_name = "config" verbose_name_plural = _("Config") abstract = False swapped = False is_composite_pk = False def get_change_permission(self): return f"change_{self.model_name}" @property def app_config(self): return apps.get_app_config(self.app_label) @property def label(self): return f"{self.app_label}.{self.object_name}" @property def label_lower(self): return f"{self.app_label}.{self.model_name}" def get_ordered_objects(self): return False _meta = Meta() # noinspection PyTypeChecker site.unregister([Config]) # noinspection PyTypeChecker site.register([ConstanceConfig], BaseConstanceAdmin) site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] site.site_header = "eVibes" site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0]