from contextlib import suppress 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 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, ModelAdmin): 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", ) 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