diff --git a/admin_panel/management/commands/send_daily_report.py b/admin_panel/management/commands/send_daily_report.py index b399dd9..1621fd7 100644 --- a/admin_panel/management/commands/send_daily_report.py +++ b/admin_panel/management/commands/send_daily_report.py @@ -97,7 +97,8 @@ class Command(BaseCommand): # آمار نظرسنجی‌ها nazar_stats = Action.objects.filter( nazarDT__range=(today_start, today_end), - grade__gt=0 + grade__gt=0, + deleted_at__isnull=True, ).aggregate( avg_grade=Avg('grade'), total_count=Count('id') diff --git a/admin_panel/migrations/0080_action_soft_delete.py b/admin_panel/migrations/0080_action_soft_delete.py new file mode 100644 index 0000000..757c4fc --- /dev/null +++ b/admin_panel/migrations/0080_action_soft_delete.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.25 on 2026-10-21 12:31 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('admin_panel', '0079_customer_visit_hold'), + ] + + operations = [ + migrations.AddField( + model_name='action', + name='deleted_at', + field=models.DateTimeField(blank=True, default=None, help_text='اگر پر باشد، این اقدام توسط کاربر حذف شده است (status=cancell).', null=True, verbose_name='زمان حذف'), + ), + migrations.AddField( + model_name='action', + name='deleted_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='deleted_actions', to=settings.AUTH_USER_MODEL, verbose_name='حذف\u200cکننده'), + ), + ] diff --git a/admin_panel/models/actions.py b/admin_panel/models/actions.py index e85eeba..057aec6 100644 --- a/admin_panel/models/actions.py +++ b/admin_panel/models/actions.py @@ -67,6 +67,25 @@ class Action(models.Model): nazarDT = models.DateTimeField(null=True, blank=True, default=None) grade = models.IntegerField(null=True, blank=True, default=None) + # --- حسابرسی «حذف» (soft-delete از طریق status='cancell') --- + # چرا ستون جدا؟ چون ``cancell`` از قبل معنای «لغو برنامه» را دارد و در گزارش‌ها + # هم استفاده می‌شود. با این دو ستون می‌توانیم «حذف توسط کاربر» را از «لغو + # عادی» تفکیک کنیم، بدون آنکه منطق محاسبات (که فقط waite/finish را می‌بیند) + # دست بخورد. + deleted_at = models.DateTimeField( + null=True, blank=True, default=None, verbose_name="زمان حذف", + help_text="اگر پر باشد، این اقدام توسط کاربر حذف شده است (status=cancell).", + ) + deleted_by = models.ForeignKey( + User, on_delete=models.SET_NULL, null=True, blank=True, + related_name="deleted_actions", verbose_name="حذف‌کننده", + ) + + @property + def is_deleted(self): + """آیا این اقدام با «حذف» کنار گذاشته شده است؟ (نه لغو عادی)""" + return self.deleted_at is not None + class Meta: # ایندکس **پوشا (covering)** برای محاسبهٔ «آخرین بازدید»: هر سه ستونِ لازم # برای فیلتر و تجمیع داخل خودِ ایندکس است، پس دیتابیس به جدول اصلی مراجعه diff --git a/admin_panel/templates/admin_panel/customerAction.html b/admin_panel/templates/admin_panel/customerAction.html index 89ac942..74701db 100644 --- a/admin_panel/templates/admin_panel/customerAction.html +++ b/admin_panel/templates/admin_panel/customerAction.html @@ -4,7 +4,7 @@ {% block BodyCustomer1 %} -{% include 'admin_panel/customerActionInc.html' %} +{% include 'admin_panel/customerActionInc.html' with show_delete=True %}