178 lines
7.2 KiB
Python
178 lines
7.2 KiB
Python
from django.contrib import admin
|
|
|
|
# Register your models here.
|
|
|
|
from .models import *
|
|
|
|
admin.site.register(Customer)
|
|
admin.site.register(PhoneNumber)
|
|
admin.site.register(ProductCategory)
|
|
admin.site.register(Product)
|
|
admin.site.register(ProductInStore)
|
|
admin.site.register(Factor)
|
|
admin.site.register(FactorIteam)
|
|
admin.site.register(VisitQueue)
|
|
admin.site.register(ArticleType)
|
|
admin.site.register(Article)
|
|
admin.site.register(Sarresid)
|
|
admin.site.register(Action)
|
|
admin.site.register(CacheTable)
|
|
admin.site.register(ProductStockHistory)
|
|
|
|
|
|
@admin.register(StoreTransferRequest)
|
|
class StoreTransferRequestAdmin(admin.ModelAdmin):
|
|
# ۱. حل مشکل لودینگ و هنگ کردن فرم (تبدیل منوی کشویی غولآسا به باکس شناسه عددی)
|
|
# این دستور فیلدهای پرجمعیت را به شدت بهینه و سبک میکند
|
|
raw_id_fields = ['out_transaction', 'in_transaction', 'product', 'requester', 'approver']
|
|
|
|
# ۲. ستونهایی که میخواهید در صفحه جدول (Changelist) نمایش داده شوند
|
|
list_display = [
|
|
'id',
|
|
'source_store',
|
|
'target_store',
|
|
'product',
|
|
'quantity',
|
|
'status',
|
|
'created_at',
|
|
'action_date'
|
|
]
|
|
|
|
# ۳. فیکس قطعی باگ N+1 (لود کردن روابط در یک کوئری واحد به جای صدها کوئری تودرتو برای __str__)
|
|
list_select_related = ['source_store', 'target_store', 'product', 'requester', 'approver']
|
|
|
|
# ۴. فیلترهای سمت راست صفحه (فقط روی فیلدهای کمجمعیت مثل وضعیت و انبار فیلتر بگذارید)
|
|
list_filter = ['status', 'source_store', 'target_store', 'created_at']
|
|
|
|
# ۵. باکس جستجوی بهینه شده
|
|
search_fields = ['id', 'desc', 'product__product_name', 'requester__username']
|
|
|
|
# ۶. غیرقابل ادیت کردن فیلدهای حساس مالی در پنل ادمین (اختیاری اما برای Enterprise الزامی است)
|
|
readonly_fields = ['created_at', 'updated_at']
|
|
|
|
class StoreRoomOwnerInline(admin.TabularInline):
|
|
"""
|
|
این کلاس باعث میشود مالکین انبار به صورت یک جدول کوچک
|
|
در داخل همان صفحه مدیریت انبار نمایش داده شوند.
|
|
"""
|
|
model = StoreRoomOwner
|
|
extra = 1 # تعداد ردیفهای خالی برای افزودن مالک جدید
|
|
verbose_name = "مالک انبار"
|
|
verbose_name_plural = "مالکین انبار"
|
|
|
|
@admin.register(StoreRoom)
|
|
class StoreRoomAdmin(admin.ModelAdmin):
|
|
list_display = ('store_name', 'get_owners_count')
|
|
search_fields = ('store_name',)
|
|
|
|
# فیلد user یک M2M معمولی است، پس filter_horizontal روی آن عالی کار میکند
|
|
filter_horizontal = ('user',)
|
|
|
|
# فیلد owners چون جدول واسط دارد، باید از طریق Inline مدیریت شود
|
|
inlines = [StoreRoomOwnerInline]
|
|
|
|
def get_owners_count(self, obj):
|
|
"""نمایش تعداد مالکین در لیست اصلی انبارها"""
|
|
return obj.owners.count()
|
|
get_owners_count.short_description = "تعداد مالکین"
|
|
|
|
# ============================================================
|
|
# مدیریت پیامک (SMS)
|
|
# ============================================================
|
|
from django import forms
|
|
from django.contrib import messages
|
|
|
|
|
|
class SMSProviderConfigForm(forms.ModelForm):
|
|
class Meta:
|
|
model = SMSProviderConfig
|
|
fields = '__all__'
|
|
widgets = {
|
|
'password': forms.PasswordInput(render_value=True),
|
|
'api_token': forms.PasswordInput(render_value=True),
|
|
}
|
|
|
|
|
|
@admin.register(SMSProviderConfig)
|
|
class SMSProviderConfigAdmin(admin.ModelAdmin):
|
|
form = SMSProviderConfigForm
|
|
list_display = ('provider', 'is_enabled', 'sender', 'username',
|
|
'allow_backlog', 'backlog_max', 'max_per_run',
|
|
'send_interval_seconds', 'updated_at')
|
|
readonly_fields = ('updated_at',)
|
|
fieldsets = (
|
|
("اتصال سرویسدهنده", {
|
|
'fields': ('provider', 'is_enabled', 'api_url', 'username', 'password',
|
|
'sender', 'api_token', 'test_message', 'timeout_seconds'),
|
|
}),
|
|
("وبسرویس ۰۰۹۸ (فقط provider وبسرویس)", {
|
|
'fields': ('webservice_url', 'panel_no'),
|
|
}),
|
|
("کنترل جریان ارسال", {
|
|
'fields': ('scan_since', 'allow_backlog', 'backlog_max',
|
|
'max_per_run', 'send_interval_seconds', 'updated_at'),
|
|
}),
|
|
)
|
|
|
|
def has_add_permission(self, request):
|
|
# سینگلتون: فقط ویرایش رکورد موجود.
|
|
return not SMSProviderConfig.objects.exists()
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
|
|
@admin.register(SMSTemplate)
|
|
class SMSTemplateAdmin(admin.ModelAdmin):
|
|
list_display = ('title', 'sms_type', 'is_enabled', 'auto_send', 'offset_days',
|
|
'repeat_interval_days', 'repeat_interval_months')
|
|
list_editable = ('is_enabled', 'auto_send')
|
|
list_filter = ('sms_type', 'is_enabled', 'auto_send')
|
|
search_fields = ('title', 'text')
|
|
readonly_fields = ('updated_at',)
|
|
|
|
|
|
@admin.register(CustomerSMSSetting)
|
|
class CustomerSMSSettingAdmin(admin.ModelAdmin):
|
|
list_display = ('customer', 'sms_type', 'is_enabled')
|
|
list_filter = ('sms_type', 'is_enabled')
|
|
raw_id_fields = ('customer',)
|
|
search_fields = ('customer__name_family',)
|
|
|
|
|
|
@admin.register(SMSQueue)
|
|
class SMSQueueAdmin(admin.ModelAdmin):
|
|
list_display = ('id', 'customer', 'sms_type', 'phone_number', 'status',
|
|
'delivery_status', 'attempts', 'created_at', 'sent_at')
|
|
list_filter = ('status', 'sms_type', 'delivery_status')
|
|
raw_id_fields = ('customer', 'created_by')
|
|
search_fields = ('phone_number', 'message', 'dedup_key')
|
|
readonly_fields = ('created_at', 'updated_at', 'sent_at')
|
|
actions = ['approve_selected', 'retry_selected']
|
|
|
|
@admin.action(description="تأیید موارد انتخابشده (ارسال توسط worker)")
|
|
def approve_selected(self, request, queryset):
|
|
updated = queryset.filter(status=SMSQueue.Status.PENDING).update(
|
|
status=SMSQueue.Status.APPROVED, next_retry_at=None,
|
|
)
|
|
self.message_user(request, f"{updated} پیامک تأیید شد.", messages.SUCCESS)
|
|
|
|
@admin.action(description="ارسال مجدد موارد انتخابشده")
|
|
def retry_selected(self, request, queryset):
|
|
updated = queryset.update(status=SMSQueue.Status.APPROVED, next_retry_at=None, last_error='')
|
|
self.message_user(request, f"{updated} پیامک برای ارسال مجدد تأیید شد.", messages.SUCCESS)
|
|
|
|
|
|
@admin.register(SMSLog)
|
|
class SMSLogAdmin(admin.ModelAdmin):
|
|
list_display = ('id', 'queue', 'attempt_no', 'success', 'provider_code', 'created_at')
|
|
list_filter = ('success',)
|
|
raw_id_fields = ('queue',)
|
|
readonly_fields = ('queue', 'attempt_no', 'success', 'provider_id', 'provider_code', 'error', 'created_at')
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return False
|