import re import random import string from django.db import models from django.utils.translation import gettext_lazy as _ from django_tidb.fields import BigAutoRandomField from django.conf import settings from django.core.exceptions import ValidationError CREDIT_VOUCHER_PATTERN = re.compile( r"^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$" ) def credit_code_generator(): random_chars = "".join(random.choices(string.ascii_uppercase + string.digits, k=25)) formatted_string = "-".join(random_chars[i : i + 5] for i in range(0, 25, 5)) return formatted_string def credit_code_validator(value): if not CREDIT_VOUCHER_PATTERN.match(value): raise ValidationError("Invalid credit code format") def credits_validator(value): if value < 1: raise ValidationError("Credit must be greater than 0") class CreditVoucher(models.Model): class UsedChoices(models.TextChoices): N = "N" Y = "Y" id = BigAutoRandomField(primary_key=True) unique_code = models.CharField( max_length=29, unique=True, default=credit_code_generator, help_text="The unique code of the credit voucher", validators=[credit_code_validator], ) credits = models.IntegerField( null=True, validators=[credits_validator], help_text="The exchange rate with the USD is 1:1", ) valid_before = models.DateField(null=True) used = models.CharField( max_length=1, default=UsedChoices.N, choices=UsedChoices.choices ) marketing_code = models.CharField(max_length=100) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) category = models.CharField(max_length=30, default="Others") customer_organization = models.CharField(max_length=100, default="N/A") redeem_at = models.DateTimeField(blank=True, null=True) redeem_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, blank=True, null=True, ) class Meta: db_table = "credit_vouchers" managed = False