You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
7.8 KiB
201 lines
7.8 KiB
from django.core.management.base import BaseCommand, CommandError
|
|
from django.db import transaction
|
|
from django.utils import timezone
|
|
from apps.transaction.models import TransactionParticipant
|
|
from apps.course.models import Participant
|
|
from apps.account.models import User
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'بررسی تراکنشهای موفق و ایجاد شرکتکنندگان دوره در صورت عدم وجود'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--dry-run',
|
|
action='store_true',
|
|
help='فقط نمایش تراکنشهایی که نیاز به بروزرسانی دارند بدون اعمال تغییرات',
|
|
)
|
|
parser.add_argument(
|
|
'--transaction-id',
|
|
type=int,
|
|
help='بررسی تراکنش خاص با ID مشخص',
|
|
)
|
|
parser.add_argument(
|
|
'--user-email',
|
|
type=str,
|
|
help='بررسی تراکنشهای کاربر خاص',
|
|
)
|
|
parser.add_argument(
|
|
'--course-slug',
|
|
type=str,
|
|
help='بررسی تراکنشهای دوره خاص',
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
dry_run = options['dry_run']
|
|
transaction_id = options.get('transaction_id')
|
|
user_email = options.get('user_email')
|
|
course_slug = options.get('course_slug')
|
|
|
|
# ساخت queryset اولیه
|
|
queryset = TransactionParticipant.objects.filter(
|
|
status=TransactionParticipant.TransactionStatus.SUCCESS,
|
|
is_deleted=False
|
|
).select_related('user', 'course')
|
|
|
|
# اعمال فیلترهای اضافی
|
|
if transaction_id:
|
|
queryset = queryset.filter(id=transaction_id)
|
|
|
|
if user_email:
|
|
try:
|
|
user = User.objects.get(email=user_email)
|
|
queryset = queryset.filter(user=user)
|
|
except User.DoesNotExist:
|
|
raise CommandError(f'کاربر با ایمیل {user_email} یافت نشد.')
|
|
|
|
if course_slug:
|
|
queryset = queryset.filter(course__slug=course_slug)
|
|
|
|
total_transactions = queryset.count()
|
|
|
|
if total_transactions == 0:
|
|
self.stdout.write(
|
|
self.style.WARNING('هیچ تراکنش موفقی برای بررسی یافت نشد.')
|
|
)
|
|
return
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(f'تعداد {total_transactions} تراکنش موفق برای بررسی یافت شد.')
|
|
)
|
|
|
|
missing_participants = []
|
|
existing_participants = []
|
|
errors = []
|
|
|
|
# بررسی هر تراکنش
|
|
for trans in queryset:
|
|
try:
|
|
# بررسی وجود participant
|
|
participant_exists = Participant.objects.filter(
|
|
student=trans.user,
|
|
course=trans.course
|
|
).exists()
|
|
|
|
if not participant_exists:
|
|
missing_participants.append(trans)
|
|
self.stdout.write(
|
|
self.style.WARNING(
|
|
f'❌ تراکنش {trans.id}: کاربر {trans.user.email} در دوره "{trans.course.title}" ثبتنام نشده'
|
|
)
|
|
)
|
|
else:
|
|
existing_participants.append(trans)
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f'✅ تراکنش {trans.id}: کاربر {trans.user.email} در دوره "{trans.course.title}" قبلاً ثبتنام شده'
|
|
)
|
|
)
|
|
|
|
except Exception as e:
|
|
errors.append((trans, str(e)))
|
|
self.stdout.write(
|
|
self.style.ERROR(
|
|
f'⚠️ خطا در بررسی تراکنش {trans.id}: {str(e)}'
|
|
)
|
|
)
|
|
|
|
# نمایش خلاصه
|
|
self.stdout.write('\n' + '='*50)
|
|
self.stdout.write(f'📊 خلاصه نتایج:')
|
|
self.stdout.write(f' • کل تراکنشهای بررسی شده: {total_transactions}')
|
|
self.stdout.write(f' • شرکتکنندگان موجود: {len(existing_participants)}')
|
|
self.stdout.write(f' • شرکتکنندگان ناموجود: {len(missing_participants)}')
|
|
self.stdout.write(f' • خطاها: {len(errors)}')
|
|
self.stdout.write('='*50 + '\n')
|
|
|
|
if not missing_participants:
|
|
self.stdout.write(
|
|
self.style.SUCCESS('🎉 همه تراکنشهای موفق دارای شرکتکننده مربوطه هستند!')
|
|
)
|
|
return
|
|
|
|
if dry_run:
|
|
self.stdout.write(
|
|
self.style.WARNING(
|
|
f'🔍 حالت Dry Run: {len(missing_participants)} شرکتکننده نیاز به ایجاد دارند.'
|
|
)
|
|
)
|
|
self.stdout.write(
|
|
'برای اعمال تغییرات، دستور را بدون --dry-run اجرا کنید.'
|
|
)
|
|
return
|
|
|
|
# ایجاد شرکتکنندگان ناموجود
|
|
created_count = 0
|
|
failed_count = 0
|
|
|
|
self.stdout.write(
|
|
self.style.SUCCESS(f'🚀 شروع ایجاد {len(missing_participants)} شرکتکننده...')
|
|
)
|
|
|
|
for trans in missing_participants:
|
|
try:
|
|
with transaction.atomic():
|
|
# اضافه کردن نقش student اگر وجود نداشته باشد
|
|
if not trans.user.has_role('student'):
|
|
trans.user.add_role('student')
|
|
self.stdout.write(
|
|
f' 👤 نقش student به کاربر {trans.user.email} اضافه شد'
|
|
)
|
|
|
|
# ایجاد participant
|
|
participant = Participant.objects.create(
|
|
student=trans.user,
|
|
course=trans.course
|
|
)
|
|
|
|
created_count += 1
|
|
self.stdout.write(
|
|
self.style.SUCCESS(
|
|
f' ✅ شرکتکننده ایجاد شد: {trans.user.email} در دوره "{trans.course.title}"'
|
|
)
|
|
)
|
|
|
|
except Exception as e:
|
|
failed_count += 1
|
|
self.stdout.write(
|
|
self.style.ERROR(
|
|
f' ❌ خطا در ایجاد شرکتکننده برای تراکنش {trans.id}: {str(e)}'
|
|
)
|
|
)
|
|
|
|
# نمایش نتیجه نهایی
|
|
self.stdout.write('\n' + '='*50)
|
|
self.stdout.write('🏁 نتیجه نهایی:')
|
|
self.stdout.write(f' • شرکتکنندگان ایجاد شده: {created_count}')
|
|
self.stdout.write(f' • شکستها: {failed_count}')
|
|
|
|
if created_count > 0:
|
|
self.stdout.write(
|
|
self.style.SUCCESS(f'✅ {created_count} شرکتکننده با موفقیت ایجاد شد!')
|
|
)
|
|
|
|
if failed_count > 0:
|
|
self.stdout.write(
|
|
self.style.ERROR(f'❌ {failed_count} مورد با خطا مواجه شد!')
|
|
)
|
|
|
|
self.stdout.write('='*50)
|
|
|
|
def get_transaction_info(self, trans):
|
|
"""اطلاعات کامل تراکنش را برمیگرداند"""
|
|
return {
|
|
'id': trans.id,
|
|
'user_email': trans.user.email,
|
|
'course_title': trans.course.title,
|
|
'course_slug': trans.course.slug,
|
|
'price': trans.price,
|
|
'created_at': trans.created_at,
|
|
'status': trans.status
|
|
}
|