feat(events): harden registration checkout lifecycle
This commit is contained in:
@@ -81,6 +81,12 @@ class Payment(BaseModel):
|
||||
FAILED = 3, "Failed"
|
||||
CANCELED = 4, "Canceled"
|
||||
|
||||
class RefundStatusChoices(models.TextChoices):
|
||||
NONE = "none", "No refund required"
|
||||
PENDING = "pending", "Refund pending"
|
||||
SUCCEEDED = "succeeded", "Refund completed"
|
||||
MANUAL_REVIEW = "manual_review", "Refund needs review"
|
||||
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name='payments', editable=False)
|
||||
event = models.ForeignKey(Event, on_delete=models.PROTECT, related_name='payments', editable=False)
|
||||
|
||||
@@ -104,6 +110,24 @@ class Payment(BaseModel):
|
||||
card_pan = models.CharField(max_length=32, null=True, blank=True, editable=False)
|
||||
card_hash = models.CharField(max_length=128, null=True, blank=True, editable=False)
|
||||
verified_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
gateway_paid_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
verification_attempts = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
verification_last_attempt_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
verification_next_attempt_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
verification_lease_until = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
verification_dispatch_expires_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
verification_manual_review_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
refund_status = models.CharField(
|
||||
max_length=20,
|
||||
choices=RefundStatusChoices.choices,
|
||||
default=RefundStatusChoices.NONE,
|
||||
editable=False,
|
||||
)
|
||||
refund_attempts = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
refund_last_attempt_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
refund_next_attempt_at = models.DateTimeField(null=True, blank=True, editable=False)
|
||||
refund_reference = models.CharField(max_length=64, null=True, blank=True, editable=False)
|
||||
refund_last_error = models.CharField(max_length=255, blank=True, default='', editable=False)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
@@ -127,5 +151,24 @@ class Payment(BaseModel):
|
||||
"""Human-readable label for the payment status."""
|
||||
return self.get_status_display()
|
||||
|
||||
@property
|
||||
def verification_state(self):
|
||||
"""Server-owned verification state for callback and support screens."""
|
||||
if self.status == self.OrderStatusChoices.PAID or self.verified_at is not None:
|
||||
return "verified"
|
||||
if self.status == self.OrderStatusChoices.FAILED:
|
||||
return "failed"
|
||||
if self.status == self.OrderStatusChoices.CANCELED:
|
||||
return "canceled"
|
||||
if self.verification_manual_review_at is not None or not self.authority:
|
||||
return "manual_review"
|
||||
|
||||
now = timezone.now()
|
||||
if self.verification_lease_until and self.verification_lease_until > now:
|
||||
return "checking"
|
||||
if self.verification_next_attempt_at:
|
||||
return "retry_scheduled"
|
||||
return "awaiting_verification"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.email}:{self.event} - {self.get_status_display()}"
|
||||
|
||||
Reference in New Issue
Block a user