160 lines
4.6 KiB
Python
160 lines
4.6 KiB
Python
from decimal import Decimal
|
|
|
|
from django.contrib import messages
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
from django.utils import timezone
|
|
|
|
from products.models import Product
|
|
|
|
from .models import Coupon
|
|
|
|
|
|
def get_cart(request):
|
|
return request.session.get('cart', {})
|
|
|
|
|
|
def save_cart(request, cart):
|
|
request.session['cart'] = cart
|
|
request.session.modified = True
|
|
|
|
|
|
def _redirect_after_add(request):
|
|
next_url = request.GET.get('next', '').strip()
|
|
if next_url.startswith('/'):
|
|
return redirect(next_url)
|
|
return redirect('cart')
|
|
|
|
|
|
def add_to_cart(request, id):
|
|
product = get_object_or_404(Product, id=id)
|
|
cart = get_cart(request)
|
|
current_qty = cart.get(str(id), 0)
|
|
|
|
if current_qty + 1 > product.stock:
|
|
messages.warning(request, f'Only {product.stock} units of {product.name} are available.')
|
|
else:
|
|
cart[str(id)] = current_qty + 1
|
|
messages.success(request, f'Added {product.name} to your cart.')
|
|
|
|
save_cart(request, cart)
|
|
return _redirect_after_add(request)
|
|
|
|
|
|
def buy_now(request, id):
|
|
product = get_object_or_404(Product, id=id)
|
|
if product.stock <= 0:
|
|
messages.error(request, f'{product.name} is out of stock.')
|
|
return redirect('product_detail', product_id=product.id)
|
|
|
|
request.session['buy_now'] = {str(product.id): 1}
|
|
request.session.modified = True
|
|
messages.info(request, f'Proceeding to checkout for {product.name}.')
|
|
return redirect('checkout')
|
|
|
|
|
|
def update_cart(request, id):
|
|
if request.method == 'POST':
|
|
qty = int(request.POST.get('quantity', 1))
|
|
product = get_object_or_404(Product, id=id)
|
|
cart = get_cart(request)
|
|
|
|
if qty <= 0:
|
|
cart.pop(str(id), None)
|
|
messages.info(request, f'{product.name} removed from cart.')
|
|
elif qty > product.stock:
|
|
cart[str(id)] = product.stock
|
|
messages.warning(request, f'Quantity adjusted to {product.stock} for {product.name}.')
|
|
else:
|
|
cart[str(id)] = qty
|
|
messages.success(request, f'Cart updated for {product.name}.')
|
|
|
|
save_cart(request, cart)
|
|
|
|
return redirect('cart')
|
|
|
|
|
|
def remove_from_cart(request, id):
|
|
cart = get_cart(request)
|
|
if str(id) in cart:
|
|
del cart[str(id)]
|
|
messages.info(request, 'Item removed from your cart.')
|
|
save_cart(request, cart)
|
|
return redirect('cart')
|
|
|
|
|
|
def _get_coupon_for_cart(code, subtotal):
|
|
if not code:
|
|
return None, Decimal('0')
|
|
|
|
now = timezone.now()
|
|
coupon = Coupon.objects.filter(code=code, active=True).first()
|
|
if not coupon:
|
|
return None, Decimal('0')
|
|
|
|
if coupon.valid_from and now < coupon.valid_from:
|
|
return None, Decimal('0')
|
|
if coupon.valid_to and now > coupon.valid_to:
|
|
return None, Decimal('0')
|
|
if subtotal < coupon.min_purchase:
|
|
return coupon, Decimal('0')
|
|
|
|
discount = (subtotal * (coupon.discount_percent / Decimal('100'))).quantize(Decimal('0.01'))
|
|
return coupon, discount
|
|
|
|
|
|
def apply_coupon(request):
|
|
if request.method == 'POST':
|
|
code = request.POST.get('coupon_code', '').strip().upper()
|
|
request.session['coupon_code'] = code
|
|
messages.success(request, f'Coupon {code} applied.')
|
|
return redirect('cart')
|
|
|
|
|
|
def remove_coupon(request):
|
|
request.session.pop('coupon_code', None)
|
|
messages.info(request, 'Coupon removed.')
|
|
return redirect('cart')
|
|
|
|
|
|
def cart_view(request):
|
|
cart = get_cart(request)
|
|
products = []
|
|
subtotal = Decimal('0')
|
|
|
|
for id, qty in cart.items():
|
|
product = get_object_or_404(Product, id=int(id))
|
|
product.qty = qty
|
|
product.subtotal = product.display_price * qty
|
|
subtotal += product.subtotal
|
|
products.append(product)
|
|
|
|
shipping = Decimal('60') if products else Decimal('0')
|
|
|
|
coupon_code = request.session.get('coupon_code', '')
|
|
coupon, discount = _get_coupon_for_cart(coupon_code, subtotal)
|
|
if coupon_code and not coupon:
|
|
request.session.pop('coupon_code', None)
|
|
messages.warning(request, 'Coupon is invalid or expired.')
|
|
coupon_code = ''
|
|
|
|
if coupon and subtotal < coupon.min_purchase:
|
|
messages.warning(request, f'Coupon requires minimum purchase of Rs. {coupon.min_purchase}.')
|
|
discount = Decimal('0')
|
|
|
|
grand_total = subtotal - discount + shipping
|
|
|
|
return render(
|
|
request,
|
|
'cart/cart.html',
|
|
{
|
|
'products': products,
|
|
'subtotal': subtotal,
|
|
'total': subtotal,
|
|
'shipping': shipping,
|
|
'discount': discount,
|
|
'grand_total': grand_total,
|
|
'coupon_code': coupon_code,
|
|
'coupon': coupon,
|
|
},
|
|
)
|