feat(events): harden registration checkout lifecycle

This commit is contained in:
2026-10-01 12:26:49 +03:30
parent 1daa755543
commit 962238c32c
29 changed files with 3048 additions and 207 deletions

View File

@@ -7,6 +7,7 @@ from core.templatetags.jalali import jdate
from apps.events.models import Event, Registration
from apps.events.resources import EventResource, RegistrationResource
from apps.events.services import verify_registration_attendance
from apps.events.checkout import cancel_event_checkouts
@admin.register(Event)
@@ -79,8 +80,14 @@ class EventAdmin(BaseModelAdmin, ImportExportModelAdmin):
@admin.action(description='Mark selected events as cancelled')
def make_cancelled(self, request, queryset):
queryset.update(status=Event.StatusChoices.CANCELLED)
self.message_user(request, f'Cancelled {queryset.count()} events.')
count = 0
for event in queryset:
if event.status != Event.StatusChoices.CANCELLED:
event.status = Event.StatusChoices.CANCELLED
event.save(update_fields=['status'])
cancel_event_checkouts(event.pk)
count += 1
self.message_user(request, f'Cancelled {count} events.')
@admin.action(description='Mark selected events as completed')
def make_completed(self, request, queryset):
@@ -93,15 +100,27 @@ class EventAdmin(BaseModelAdmin, ImportExportModelAdmin):
event.restore()
self.message_user(request, f'Restored {queryset.count()} events.')
def save_model(self, request, obj, form, change):
previous_status = None
if change and obj.pk:
previous_status = Event.all_objects.filter(pk=obj.pk).values_list("status", flat=True).first()
super().save_model(request, obj, form, change)
if previous_status != Event.StatusChoices.CANCELLED and obj.status == Event.StatusChoices.CANCELLED:
cancel_event_checkouts(obj.pk)
@admin.register(Registration)
class RegistrationAdmin(BaseModelAdmin, ImportExportModelAdmin):
resource_class = RegistrationResource
list_display = (
'user', 'event', 'status', 'registered_at', 'ticket_id',
'user', 'event', 'status', 'registered_at', 'checkout_expires_at',
'cancellation_reason', 'ticket_id',
'discount_code', 'discount_amount', 'final_price',
)
list_filter = ('status', 'event', 'is_deleted', 'registered_at', SoftDeleteListFilter)
list_filter = (
'status', 'cancellation_reason', 'event', 'is_deleted', 'registered_at',
SoftDeleteListFilter,
)
search_fields = (
'user__username', 'user__email', 'user__first_name', 'user__last_name',
'event__title', 'ticket_id',
@@ -109,13 +128,15 @@ class RegistrationAdmin(BaseModelAdmin, ImportExportModelAdmin):
readonly_fields = (
'ticket_id', 'registered_at', 'confirmation_notification_sent_at',
'cancellation_notification_sent_at', 'discount_code', 'discount_amount',
'final_price', 'deleted_at', 'attendance_verified_at',
'final_price', 'checkout_started_at', 'checkout_expires_at',
'cancellation_reason', 'deleted_at', 'attendance_verified_at',
'attendance_verified_by', 'attendance_verification_source',
)
fieldsets = (
('Registration Details', {'fields': (
'user', 'event', 'status', 'registered_at', 'ticket_id',
'confirmation_notification_sent_at', 'cancellation_notification_sent_at',
'checkout_started_at', 'checkout_expires_at', 'cancellation_reason',
)}),
('Attendance verification', {'fields': (
'attendance_verified_at', 'attendance_verified_by', 'attendance_verification_source',