""" «پرونده‌ی کاربر»: ورود، خروج و خریدهای یک کاربر به ترتیبِ زمان، برای ادمین. فقط می‌خواند؛ چیزی جدا ذخیره نمی‌کند، پس با جدول‌های اصلی (LoginEvent، Order، StatusChangeLog) هرگز ناهماهنگ نمی‌شود. تصمیمِ ادغام‌نکردنِ این‌ها در یک جدول: ستون‌هایشان فرق دارد. آزموده نشده: کاربری با ده‌ها هزار ردیف (همه‌ی ردیف‌ها در حافظه می‌آیند). """ from django.db.models import Q from django.utils import timezone from payment.models import Order from statuslog.models import StatusChangeLog from .models import LoginEvent, User _STATUS_FA = dict(Order.STATUS_CHOICES) _EVENT_FA = dict(LoginEvent.EVENT_CHOICES) COLUMNS = ['زمان', 'نوع', 'شرح', 'مبلغ', 'آی‌پی'] def user_activity(user: User) -> list[dict]: rows = [{'at': user.created_at, 'kind': 'ثبت‌نام', 'detail': '', 'amount': '', 'ip': ''}] # ورودِ ناموفق هنوز user_id ندارد (کاربر معلوم نیست)، پس با شماره هم می‌گیریم. by_user = Q(user_id=user.id) | (Q(phone=user.phone) if user.phone else Q(pk__in=[])) for e in LoginEvent.objects.filter(by_user): rows.append({'at': e.created_at, 'kind': _EVENT_FA.get(e.event, e.event), 'detail': e.user_agent[:80], 'amount': '', 'ip': e.ip or ''}) orders = list(Order.objects.filter(user_id=user.id)) for o in orders: rows.append({ 'at': o.created_at, 'kind': 'سفارش', 'detail': f'#{o.id} {o.plan_title or "بدون پلن"} ({o.get_provider_display()})', 'amount': f'{o.amount} {o.currency}', 'ip': '', }) for c in StatusChangeLog.objects.filter(label='payment.Order', object_id__in=[o.id for o in orders]): rows.append({ 'at': c.created_at, 'kind': 'تغییر وضعیت سفارش', 'detail': f'#{c.object_id}: {_STATUS_FA.get(c.old_status, c.old_status or "—")} ← ' f'{_STATUS_FA.get(c.new_status, c.new_status)} ({c.event})', 'amount': '', 'ip': '', }) rows.sort(key=lambda r: r['at']) for r in rows: r['at_local'] = timezone.localtime(r['at']).strftime('%Y-%m-%d %H:%M:%S') return rows