1193 lines
26 KiB
Python
1193 lines
26 KiB
Python
from contextlib import suppress
|
|
from typing import Any, Callable, ClassVar, Type
|
|
|
|
from constance.admin import Config
|
|
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
|
from django.apps import AppConfig, apps
|
|
from django.conf import settings
|
|
from django.contrib.admin import register, site
|
|
from django.contrib.gis.admin import GISModelAdmin
|
|
from django.contrib.messages import constants as messages
|
|
from django.db.models import Model
|
|
from django.db.models.query import QuerySet
|
|
from django.http import HttpRequest
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django_celery_beat.admin import ClockedScheduleAdmin as BaseClockedScheduleAdmin
|
|
from django_celery_beat.admin import CrontabScheduleAdmin as BaseCrontabScheduleAdmin
|
|
from django_celery_beat.admin import PeriodicTaskAdmin as BasePeriodicTaskAdmin
|
|
from django_celery_beat.admin import PeriodicTaskForm, TaskSelectWidget
|
|
from django_celery_beat.models import (
|
|
ClockedSchedule,
|
|
CrontabSchedule,
|
|
IntervalSchedule,
|
|
PeriodicTask,
|
|
SolarSchedule,
|
|
)
|
|
from djangoql.admin import DjangoQLSearchMixin
|
|
from import_export.admin import ImportExportModelAdmin
|
|
from modeltranslation.translator import NotRegistered, translator
|
|
from modeltranslation.utils import get_translation_fields
|
|
from mptt.admin import DraggableMPTTAdmin
|
|
from unfold.admin import ModelAdmin, TabularInline
|
|
from unfold.contrib.import_export.forms import ExportForm, ImportForm
|
|
from unfold.decorators import action
|
|
from unfold.typing import FieldsetsType
|
|
from unfold.widgets import UnfoldAdminSelectWidget, UnfoldAdminTextInputWidget
|
|
|
|
from engine.core.forms import (
|
|
CRMForm,
|
|
OrderForm,
|
|
OrderProductForm,
|
|
StockForm,
|
|
VendorForm,
|
|
)
|
|
from engine.core.models import (
|
|
Address,
|
|
Attribute,
|
|
AttributeGroup,
|
|
AttributeValue,
|
|
Brand,
|
|
Category,
|
|
CategoryTag,
|
|
CustomerRelationshipManagementProvider,
|
|
Feedback,
|
|
Order,
|
|
OrderCrmLink,
|
|
OrderProduct,
|
|
Product,
|
|
ProductImage,
|
|
ProductTag,
|
|
PromoCode,
|
|
Promotion,
|
|
Stock,
|
|
Vendor,
|
|
Wishlist,
|
|
)
|
|
|
|
|
|
class FieldsetsMixin:
|
|
general_fields: list[str] | None = []
|
|
relation_fields: list[str] | None = []
|
|
additional_fields: list[str] | None = []
|
|
model: ClassVar[Type[Model]]
|
|
|
|
def get_fieldsets(self, request: HttpRequest, obj: Any = None) -> FieldsetsType:
|
|
if request:
|
|
pass
|
|
|
|
if obj:
|
|
pass
|
|
|
|
fieldsets = []
|
|
|
|
def add_translations_fieldset(
|
|
fss: FieldsetsType,
|
|
) -> FieldsetsType:
|
|
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"),
|
|
{"classes": ["tab"], "fields": translation_fields},
|
|
)
|
|
]
|
|
return fss
|
|
|
|
if self.general_fields:
|
|
fieldsets.append(
|
|
(_("general"), {"classes": ["tab"], "fields": self.general_fields})
|
|
)
|
|
if self.relation_fields:
|
|
fieldsets.append(
|
|
(_("relations"), {"classes": ["tab"], "fields": self.relation_fields})
|
|
)
|
|
if self.additional_fields:
|
|
fieldsets.append(
|
|
(
|
|
_("additional info"),
|
|
{"classes": ["tab"], "fields": self.additional_fields},
|
|
)
|
|
)
|
|
opts = self.model._meta
|
|
|
|
meta_fields = []
|
|
|
|
if any(f.name == "uuid" for f in opts.fields):
|
|
meta_fields.append("uuid")
|
|
|
|
if any(f.name == "slug" for f in opts.fields):
|
|
meta_fields.append("slug")
|
|
|
|
if any(f.name == "sku" for f in opts.fields):
|
|
meta_fields.append("sku")
|
|
|
|
if any(f.name == "human_readable_id" for f in opts.fields):
|
|
meta_fields.append("human_readable_id")
|
|
|
|
if meta_fields:
|
|
fieldsets.append(
|
|
(_("metadata"), {"classes": ["tab"], "fields": meta_fields})
|
|
)
|
|
|
|
ts = []
|
|
for name in ("created", "modified"):
|
|
if any(f.name == name for f in opts.fields):
|
|
ts.append(name)
|
|
if ts:
|
|
fieldsets.append((_("timestamps"), {"classes": ["tab"], "fields": ts}))
|
|
fieldsets = add_translations_fieldset(fieldsets)
|
|
return fieldsets
|
|
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
class ActivationActionsMixin:
|
|
message_user: Callable
|
|
actions_on_top = True
|
|
actions_on_bottom = True
|
|
actions = [
|
|
"delete_selected",
|
|
"activate_selected",
|
|
"deactivate_selected",
|
|
]
|
|
|
|
@action(
|
|
description=_("activate selected %(verbose_name_plural)s").lower().title(),
|
|
permissions=["change"],
|
|
)
|
|
def activate_selected(self, request: HttpRequest, queryset: QuerySet[Any]) -> None:
|
|
try:
|
|
queryset.update(is_active=True)
|
|
self.message_user(
|
|
request=request,
|
|
message=_("selected items have been activated.").lower().title(),
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
except Exception as e:
|
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
|
|
|
@action(
|
|
description=_("deactivate selected %(verbose_name_plural)s").lower().title(),
|
|
permissions=["change"],
|
|
)
|
|
def deactivate_selected(
|
|
self, request: HttpRequest, queryset: QuerySet[Any]
|
|
) -> None:
|
|
try:
|
|
queryset.update(is_active=False)
|
|
self.message_user(
|
|
request=request,
|
|
message=_("selected items have been deactivated.").lower().title(),
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
except Exception as e:
|
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
|
|
|
|
|
class AttributeValueInline(TabularInline):
|
|
model = AttributeValue
|
|
extra = 0
|
|
autocomplete_fields = ["attribute"]
|
|
verbose_name = _("attribute value")
|
|
verbose_name_plural = _("attribute values")
|
|
tab = True
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).select_related("attribute", "product")
|
|
|
|
|
|
class ProductImageInline(TabularInline):
|
|
model = ProductImage
|
|
extra = 0
|
|
tab = True
|
|
verbose_name = _("image")
|
|
verbose_name_plural = _("images")
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).select_related("product")
|
|
|
|
|
|
class StockInline(TabularInline):
|
|
model = Stock
|
|
extra = 0
|
|
form = StockForm
|
|
tab = True
|
|
verbose_name = _("stock")
|
|
verbose_name_plural = _("stocks")
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).select_related("vendor", "product")
|
|
|
|
|
|
class OrderProductInline(TabularInline):
|
|
model = OrderProduct
|
|
extra = 0
|
|
readonly_fields = ("product", "quantity", "buy_price")
|
|
form = OrderProductForm
|
|
verbose_name = _("order product")
|
|
verbose_name_plural = _("order products")
|
|
tab = True
|
|
|
|
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")
|
|
tab = True
|
|
verbose_name = _("children")
|
|
verbose_name_plural = _("children")
|
|
|
|
|
|
@register(AttributeGroup)
|
|
class AttributeGroupAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = AttributeGroup
|
|
list_display = (
|
|
"name",
|
|
"modified",
|
|
)
|
|
search_fields = (
|
|
"uuid",
|
|
"name",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"parent",
|
|
]
|
|
|
|
|
|
@register(Attribute)
|
|
class AttributeAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
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 = [
|
|
"group",
|
|
]
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"value_type",
|
|
"is_filterable",
|
|
]
|
|
relation_fields = [
|
|
"group",
|
|
]
|
|
|
|
|
|
@register(AttributeValue)
|
|
class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin):
|
|
# noinspection PyClassVar
|
|
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(
|
|
DjangoQLSearchMixin,
|
|
FieldsetsMixin,
|
|
ActivationActionsMixin,
|
|
DraggableMPTTAdmin,
|
|
ModelAdmin,
|
|
):
|
|
# noinspection PyClassVar
|
|
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(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = Brand
|
|
list_display = (
|
|
"name",
|
|
"priority",
|
|
"is_active",
|
|
)
|
|
list_filter = (
|
|
"categories",
|
|
"is_active",
|
|
)
|
|
search_fields = (
|
|
"uuid",
|
|
"name",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"slug",
|
|
"modified",
|
|
"created",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"description",
|
|
"priority",
|
|
]
|
|
additional_fields = ["small_logo", "big_logo"]
|
|
|
|
|
|
@register(Product)
|
|
class ProductAdmin(
|
|
DjangoQLSearchMixin,
|
|
FieldsetsMixin,
|
|
ActivationActionsMixin,
|
|
ModelAdmin,
|
|
ImportExportModelAdmin,
|
|
):
|
|
# noinspection PyClassVar
|
|
model = Product
|
|
list_display = (
|
|
"sku",
|
|
"name",
|
|
"is_active",
|
|
"export_to_marketplaces",
|
|
"has_images",
|
|
"category",
|
|
"brand",
|
|
"price",
|
|
"rating",
|
|
"modified",
|
|
)
|
|
list_filter = (
|
|
"is_active",
|
|
"is_digital",
|
|
"is_updatable",
|
|
"stocks__vendor",
|
|
"tags__name",
|
|
"created",
|
|
"modified",
|
|
)
|
|
search_fields = (
|
|
"name",
|
|
"partnumber",
|
|
"brand__name",
|
|
"brand__slug",
|
|
"category__name",
|
|
"category__slug",
|
|
"uuid",
|
|
"slug",
|
|
"sku",
|
|
)
|
|
readonly_fields = (
|
|
"sku",
|
|
"slug",
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
autocomplete_fields = (
|
|
"category",
|
|
"brand",
|
|
"tags",
|
|
)
|
|
inlines = [
|
|
AttributeValueInline,
|
|
ProductImageInline,
|
|
StockInline,
|
|
]
|
|
import_form_class = ImportForm
|
|
export_form_class = ExportForm
|
|
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"partnumber",
|
|
"is_digital",
|
|
]
|
|
relation_fields = [
|
|
"category",
|
|
"brand",
|
|
"tags",
|
|
]
|
|
additional_fields = [
|
|
"is_updatable",
|
|
]
|
|
|
|
def has_images(self, obj: Product) -> bool:
|
|
return obj.has_images
|
|
|
|
has_images.boolean = True # ty:ignore[unresolved-attribute]
|
|
has_images.short_description = _("has images") # ty:ignore[unresolved-attribute]
|
|
|
|
@action(
|
|
description=_("export selected %(verbose_name_plural)s to marketplaces' feeds")
|
|
.lower()
|
|
.title(),
|
|
permissions=["change"],
|
|
)
|
|
def export_to_marketplaces(
|
|
self, request: HttpRequest, queryset: QuerySet[Any]
|
|
) -> None:
|
|
try:
|
|
queryset.update(export_to_marketplaces=True)
|
|
self.message_user(
|
|
request=request,
|
|
message=_(
|
|
"selected %(verbose_name_plural)s have been marked for export."
|
|
)
|
|
.lower()
|
|
.title(),
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
except Exception as e:
|
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
|
|
|
@action(
|
|
description=_("ban selected %(verbose_name_plural)s from marketplaces' feeds")
|
|
.lower()
|
|
.title(),
|
|
permissions=["change"],
|
|
)
|
|
def ban_from_marketplaces(
|
|
self, request: HttpRequest, queryset: QuerySet[Any]
|
|
) -> None:
|
|
try:
|
|
queryset.update(export_to_marketplaces=False)
|
|
self.message_user(
|
|
request=request,
|
|
message=_(
|
|
"selected %(verbose_name_plural)s have been banned from export."
|
|
)
|
|
.lower()
|
|
.title(),
|
|
level=messages.SUCCESS,
|
|
)
|
|
|
|
except Exception as e:
|
|
self.message_user(request=request, message=str(e), level=messages.ERROR)
|
|
|
|
def get_queryset(self, request):
|
|
return (
|
|
super()
|
|
.get_queryset(request)
|
|
.select_related("category", "brand")
|
|
.prefetch_related(
|
|
"tags",
|
|
"images",
|
|
"stocks__vendor",
|
|
"attributes__attribute",
|
|
)
|
|
)
|
|
|
|
|
|
@register(ProductTag)
|
|
class ProductTagAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = ProductTag
|
|
list_display = ("tag_name",)
|
|
search_fields = ("tag_name",)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"tag_name",
|
|
"name",
|
|
]
|
|
|
|
|
|
@register(CategoryTag)
|
|
class CategoryTagAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = CategoryTag
|
|
list_display = (
|
|
"name",
|
|
"tag_name",
|
|
"is_active",
|
|
)
|
|
search_fields = (
|
|
"name",
|
|
"tag_name",
|
|
"is_active",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"tag_name",
|
|
"name",
|
|
]
|
|
|
|
|
|
@register(Vendor)
|
|
class VendorAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = Vendor
|
|
list_display = (
|
|
"name",
|
|
"markup_percent",
|
|
"modified",
|
|
)
|
|
list_filter = (
|
|
"markup_percent",
|
|
"is_active",
|
|
)
|
|
search_fields = (
|
|
"name",
|
|
"uuid",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
"last_processing_response",
|
|
)
|
|
form = VendorForm
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"markup_percent",
|
|
"authentication",
|
|
]
|
|
relation_fields = [
|
|
"users",
|
|
]
|
|
additional_fields = [
|
|
"integration_path",
|
|
"last_processing_response",
|
|
"b2b_auth_token",
|
|
]
|
|
|
|
|
|
@register(Feedback)
|
|
class FeedbackAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
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(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
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",
|
|
"notifications",
|
|
"attributes",
|
|
"buy_time",
|
|
]
|
|
relation_fields = [
|
|
"promo_code",
|
|
"billing_address",
|
|
"shipping_address",
|
|
]
|
|
|
|
|
|
@register(OrderProduct)
|
|
class OrderProductAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = OrderProduct
|
|
list_display = (
|
|
"order",
|
|
"product",
|
|
"quantity",
|
|
"buy_price",
|
|
"status",
|
|
"modified",
|
|
)
|
|
list_filter = (
|
|
"status",
|
|
"modified",
|
|
)
|
|
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(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
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",
|
|
"uuid",
|
|
"user__email",
|
|
)
|
|
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(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
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(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = Stock
|
|
form = StockForm
|
|
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",
|
|
]
|
|
additional_fields = [
|
|
"system_attributes",
|
|
]
|
|
relation_fields = [
|
|
"product",
|
|
"vendor",
|
|
]
|
|
|
|
|
|
@register(Wishlist)
|
|
class WishlistAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = Wishlist
|
|
list_display = (
|
|
"user",
|
|
"modified",
|
|
)
|
|
search_fields = (
|
|
"user__email",
|
|
"uuid",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"user",
|
|
]
|
|
relation_fields = [
|
|
"products",
|
|
]
|
|
|
|
|
|
@register(ProductImage)
|
|
class ProductImageAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = ProductImage
|
|
list_display = (
|
|
"alt",
|
|
"product",
|
|
"priority",
|
|
"modified",
|
|
)
|
|
list_filter = (
|
|
"priority",
|
|
"modified",
|
|
"created",
|
|
)
|
|
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(DjangoQLSearchMixin, FieldsetsMixin, GISModelAdmin):
|
|
# noinspection PyClassVar
|
|
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",
|
|
]
|
|
|
|
|
|
@register(CustomerRelationshipManagementProvider)
|
|
class CustomerRelationshipManagementProviderAdmin(
|
|
DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin
|
|
):
|
|
# noinspection PyClassVar
|
|
model = CustomerRelationshipManagementProvider
|
|
list_display = (
|
|
"name",
|
|
"default",
|
|
)
|
|
search_fields = (
|
|
"name",
|
|
"uuid",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
)
|
|
form = CRMForm
|
|
general_fields = [
|
|
"is_active",
|
|
"name",
|
|
"default",
|
|
"integration_url",
|
|
"integration_location",
|
|
"attributes",
|
|
"authentication",
|
|
]
|
|
|
|
|
|
@register(OrderCrmLink)
|
|
class OrderCrmLinkAdmin(DjangoQLSearchMixin, FieldsetsMixin, ModelAdmin):
|
|
# noinspection PyClassVar
|
|
model = OrderCrmLink
|
|
list_display = (
|
|
"crm_lead_id",
|
|
"order",
|
|
)
|
|
search_fields = (
|
|
"crm_lead_id",
|
|
"order__human_readable_id",
|
|
"order__uuid",
|
|
"order__user__uuid",
|
|
"order__user__email",
|
|
)
|
|
readonly_fields = (
|
|
"uuid",
|
|
"modified",
|
|
"created",
|
|
"crm_lead_id",
|
|
)
|
|
general_fields = [
|
|
"is_active",
|
|
"crm_lead_id",
|
|
]
|
|
relation_fields = [
|
|
"order",
|
|
"crm",
|
|
]
|
|
|
|
|
|
# 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) -> str:
|
|
return f"change_{self.model_name}"
|
|
|
|
@property
|
|
def app_config(self) -> AppConfig:
|
|
return apps.get_app_config(self.app_label)
|
|
|
|
@property
|
|
def label(self) -> str:
|
|
return f"{self.app_label}.{self.object_name}"
|
|
|
|
@property
|
|
def label_lower(self) -> str:
|
|
return f"{self.app_label}.{self.model_name}"
|
|
|
|
def get_ordered_objects(self) -> bool:
|
|
return False
|
|
|
|
_meta = Meta()
|
|
|
|
|
|
site.unregister([Config]) # ty:ignore[invalid-argument-type]
|
|
site.register([ConstanceConfig], BaseConstanceAdmin) # ty:ignore[invalid-argument-type]
|
|
site.site_title = settings.PROJECT_NAME
|
|
site.site_header = "Schon"
|
|
site.index_title = settings.PROJECT_NAME
|
|
|
|
|
|
site.unregister(PeriodicTask)
|
|
site.unregister(IntervalSchedule)
|
|
site.unregister(CrontabSchedule)
|
|
site.unregister(SolarSchedule)
|
|
site.unregister(ClockedSchedule)
|
|
|
|
|
|
class UnfoldTaskSelectWidget(UnfoldAdminSelectWidget, TaskSelectWidget):
|
|
pass
|
|
|
|
|
|
class UnfoldPeriodicTaskForm(PeriodicTaskForm):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.fields["task"].widget = UnfoldAdminTextInputWidget()
|
|
self.fields["regtask"].widget = UnfoldTaskSelectWidget()
|
|
|
|
|
|
@register(PeriodicTask)
|
|
class PeriodicTaskAdmin(BasePeriodicTaskAdmin, ModelAdmin):
|
|
form = UnfoldPeriodicTaskForm
|
|
|
|
|
|
@register(IntervalSchedule)
|
|
class IntervalScheduleAdmin(ModelAdmin):
|
|
pass
|
|
|
|
|
|
@register(CrontabSchedule)
|
|
class CrontabScheduleAdmin(BaseCrontabScheduleAdmin, ModelAdmin):
|
|
pass
|
|
|
|
|
|
@register(SolarSchedule)
|
|
class SolarScheduleAdmin(ModelAdmin):
|
|
pass
|
|
|
|
|
|
@register(ClockedSchedule)
|
|
class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
|
|
pass
|