I am learning to develop a ecommerce website, I have a coupon model with used and max_value, which take care of max number of coupon available to use, I want to implement that in my views, such that if the coupon is redeemed more than the max_value(number of coupons), then it should show an error message. Whatever I have tried with my limited knowledge is resulting in errors.
How can I increment the 'used' in views?
This is in much more understandable way:
users(sellers) are able to create coupons. code is the alpha numeric (which should be unique - i need to try work that out). The coupon can be used by anyone only once. max_value is set by the user who creates it, and each time someone uses coupons, the 'used' should get automatically appended. suppose there are 10 coupons, every time a customer uses one coupon, the 'used' should get incremented by 1 till it reaches max_value. if it reaches max_value, coupon should be invalid. This is what I am trying to achieve.
views
class AddCouponView(View, LoginRequiredMixin):
def post(self, *args, **kwargs):
now = timezone.now()
form = CouponForm(self.request.POST or None)
if form.is_valid():
try:
code = form.cleaned_data.get('code')
order = Order.objects.get(user=self.request.user, complete=False)
coupon_qs = Coupon.objects.filter(code__iexact=code, valid_from__lte=now,
valid_to__gte=now)
order_coupon = Order.objects.filter(coupon=coupon_qs.first(), user=self.request.user)
if order_coupon:
messages.error(self.request, 'You can\'t use same coupon again')
return redirect('store:checkout')
if coupon_qs:
order.coupon = coupon_qs[0]
order.save()
messages.success(self.request, "Successfully added coupon")
return redirect('store:checkout')
else:
messages.success(self.request, "Coupon Does not Exists")
return redirect('store:checkout')
except ObjectDoesNotExist:
messages.info(self.request, "You do not have an active order")
return redirect('store:checkout')
model
class Coupon(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
code = models.CharField(max_length=15)
amount = models.FloatField()
valid_from = models.DateTimeField(null=True)
valid_to = models.DateTimeField(null=True)
max_value = models.IntegerField(validators=[MaxValueValidator(100)], verbose_name='Coupon Quantity', null=True) # No. of coupon
used = models.IntegerField(default=0)
Thanks
How discount coupons work. A discount coupon is basically a code that a customer can enter at checkout and get a discount on their order. Offer gift cards in your store to boost up sales during the holidays. Сustomers can apply one coupon per order.
Coupon systems allow businesses to create, distribute, and track digital coupons. Such a system can also help your company analyze customers' paths to purchase, track affiliate links, prevent coupon fraud, and build customer engagement and loyalty.
If I understood correctly, maybe you can try like this:
from django.db.models import F
...
if form.is_valid():
code = form.cleaned_data.get('code')
order = Order.objects.get(user=self.request.user, complete=False)
coupon = Coupon.objects.filter(code__iexact=code, valid_from__lte=now, valid_to__gte=now).exclude(order__user=self.request.user,max_value__lte=F('used')).first()
if not coupon:
messages.error(self.request, 'You can\'t use same coupon again, or coupon does not exist')
return redirect('store:checkout')
else:
try:
coupon.used += 1
coupon.save()
order.coupon = coupon
order.save()
messages.success(self.request, "Successfully added coupon")
except:
messages.error(self.request, "Max level exceeded for coupon")
return redirect('store:checkout')
Explanation: I am querying if a coupon is valid and has exact code. I am excluding any coupon which are already used by the user using reverse relationship between Order and Coupon. If you have any related name defined in the Order
model, then the reverse query will be exclude(<related_name>__user=self.request.user)
. I am also excluding any coupon which has value of used
equals to max_value
. Then I am taking the queryset's first value and using it in the Order
object. Finally, I am adding +1 to the used
attribute of Coupon
.
You can add a constraint
in model so that it does not exceed max_value
:
from django.db.models import Q, F
class Coupon(models.Model):
...
class Meta:
constraints = [
models.CheckConstraint(check=Q(used__lte=F('max_value')), name="constrain-max-limit")
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With