2024-08-21 23:24:47 +05:30
from decimal import Decimal
2024-07-19 21:18:18 +05:30
from django . db import models
from django . utils import timezone
from accounts . models import BaseModel , IAmPrincipalType
2024-08-12 12:54:29 +05:30
from django . core . exceptions import ValidationError
2024-07-19 21:18:18 +05:30
class Coupon ( BaseModel ) :
title = models . CharField ( max_length = 255 )
coupon_code = models . CharField ( max_length = 50 , unique = True )
2024-07-31 13:12:17 +05:30
coupon_id = models . CharField ( max_length = 255 , blank = True , null = True )
2024-07-22 21:08:56 +05:30
no_of_redeems = models . IntegerField ( default = 0 )
2024-07-19 21:18:18 +05:30
description = models . TextField ( null = True , blank = True )
image = models . ImageField ( upload_to = " coupon_img " , null = True , blank = True )
discount_amount = models . DecimalField (
2024-08-21 23:24:47 +05:30
max_digits = 10 , decimal_places = 2 , null = True , blank = True , help_text = " Representing the amount to subtract from an invoice total (required if discount_percentage is not passed) "
2024-07-19 21:18:18 +05:30
)
discount_percentage = models . DecimalField (
2024-08-21 23:24:47 +05:30
max_digits = 5 , decimal_places = 2 , null = True , blank = True , help_text = " A positive float larger than 0, and smaller or equal to 100, that represents the discount the coupon will apply (required if discount_amount is not passed). "
2024-07-19 21:18:18 +05:30
)
valid_from = models . DateTimeField ( )
2024-08-21 23:24:47 +05:30
valid_to = models . DateTimeField ( help_text = " Datetime for the last redeemable date. After this, the coupon is invalid for new customers. " )
max_redeems = models . IntegerField ( default = 1 )
2024-07-19 21:18:18 +05:30
class Meta :
db_table = " coupon "
2024-08-21 23:24:47 +05:30
def __str__ ( self ) :
return self . coupon_code
2024-08-12 12:54:29 +05:30
def clean ( self ) :
"""
Validate the Coupon instance . Ensure that the ` max_redeems ` is greater than 0 ,
that either ` discount_amount ` or ` discount_percentage ` is set , and that
` valid_from ` is earlier than ` valid_to ` .
"""
if self . max_redeems < 1 :
raise ValidationError ( { " max_redeems " : " Redeems must be more than 1. " } )
# Ensure discount_amount is non-negative
if self . discount_amount is not None and self . discount_amount < 1 :
raise ValidationError (
{ " discount_amount " : " Discount amount must be more than 1. " }
)
# Ensure discount_percentage is non-negative
if self . discount_percentage is not None and self . discount_percentage < 1 :
raise ValidationError (
{ " discount_percentage " : " Discount percentage must be more than 1. " }
)
if self . discount_amount and self . discount_percentage :
raise ValidationError (
" You can only set either a discount amount or a discount percentage, not both. "
)
if not self . discount_amount and not self . discount_percentage :
raise ValidationError (
" You must set either a discount amount or a discount percentage. "
)
if self . valid_from and self . valid_to and self . valid_from > = self . valid_to :
raise ValidationError (
" The valid_from date must be earlier than the valid_to date. "
)
def save ( self , * args , * * kwargs ) :
2024-08-21 23:24:47 +05:30
from goodtimes . services import StripeService
if not self . delete :
self . clean ( ) # Call clean before saving to ensure validation
2024-08-12 12:54:29 +05:30
2024-08-21 23:24:47 +05:30
if not self . pk and not self . coupon_id :
amount_off = int ( self . discount_amount * Decimal ( 100 ) ) if self . discount_amount else None
percent_off = float ( self . discount_percentage ) if self . discount_percentage else None
result = StripeService . create_coupon (
amount_off = amount_off ,
percent_off = percent_off ,
duration = " once " ,
name = self . title ,
redeem_by = int ( self . valid_to . timestamp ( ) ) ,
max_redemptions = self . max_redeems ,
currency = ' gbp ' ,
metadata = { " local_id " : self . id }
)
if not result [ " success " ] :
raise ValueError ( f " Failed to create Stripe coupon: { result [ ' message ' ] } " )
self . coupon_code = result [ ' data ' ] . id
self . coupon_id = result [ " data " ] . id
super ( ) . save ( * args , * * kwargs )
2024-07-19 21:18:18 +05:30
2024-07-22 21:08:56 +05:30
# If max_redeems is 0, it means that we are allowing unlimited redeems
2024-08-21 23:24:47 +05:30
# def is_valid(self):
# now = timezone.now()
# return (
# self.active
# and not self.deleted
# and self.valid_from <= now <= self.valid_to
# and (self.max_redeems == 0 or self.no_of_redeems < self.max_redeems)
# )