Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django. How to reduce total number of coupons after each use

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

like image 722
Danny Avatar asked Jun 13 '20 11:06

Danny


People also ask

How discount coupons work?

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.

What is coupon system?

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.


1 Answers

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.

Update: add constrain in model

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")
        ]
like image 60
ruddra Avatar answered Sep 17 '22 12:09

ruddra