from contextlib import suppress from constance.admin import Config from constance.admin import ConstanceAdmin as BaseConstanceAdmin from djaa_list_filter.admin import AjaxAutocompleteListFilterModelAdmin 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 evibes.settings import CONSTANCE_CONFIG from .forms import OrderForm, OrderProductForm, VendorForm from .models import ( Address, Attribute, AttributeGroup, AttributeValue, Brand, Category, CategoryTag, Feedback, Order, OrderProduct, Product, ProductImage, ProductTag, PromoCode, Promotion, Stock, Vendor, Wishlist, ) class FieldsetsMixin: general_fields: list = [] relation_fields: list = [] model: 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) -> str: 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) -> str: if request: pass queryset.update(is_active=False) return str(_("%(verbose_name_plural)s deactivated successfully.")) def get_actions(self, request): 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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, AjaxAutocompleteListFilterModelAdmin): model = Product # type: ignore list_display = ( "name", "partnumber", "is_active", "category", "brand", "price", "rating", "modified", ) list_filter = ( "is_active", "is_digital", "stocks__vendor", "created", "modified", ) autocomplete_list_filter = ("category", "author", "tags") search_fields = ( "name", "partnumber", "brand__name", "category__name", "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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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 # type: ignore 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() site.unregister([Config]) # type: ignore site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore site.site_header = "eVibes" site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore