from flask import Blueprint, render_template, redirect, url_for, flash, request from flask_login import login_required, current_user from models import db, Cart, CartItem, Product cart_bp = Blueprint('cart', __name__) @cart_bp.route('/cart') @login_required def view_cart(): cart = Cart.query.filter_by(user_id=current_user.id).first() if not cart: cart = Cart(user_id=current_user.id) db.session.add(cart) db.session.commit() items = cart.items total = 0 item_details = [] for item in items: product = Product.query.get(item.product_id) if product: subtotal = product.price * item.quantity total += subtotal item_details.append({ 'id': item.id, 'product': product, 'quantity': item.quantity, 'subtotal': subtotal, 'max_quantity': product.stock }) return render_template('cart.html', items=item_details, total=total) @cart_bp.route('/add/') @login_required def add_to_cart(product_id): cart = Cart.query.filter_by(user_id=current_user.id).first() if not cart: cart = Cart(user_id=current_user.id) db.session.add(cart) db.session.commit() product = Product.query.get(product_id) if not product: flash("Product not found", "danger") return redirect(url_for('main.products')) if product.stock <= 0: flash(f"Sorry, {product.name} is out of stock", "danger") return redirect(url_for('main.products')) cart_item = CartItem.query.filter_by( cart_id=cart.id, product_id=product_id).first() if cart_item: if cart_item.quantity + 1 > product.stock: flash(f"Only {product.stock} items available in stock", "warning") return redirect(url_for('main.products')) cart_item.quantity += 1 else: cart_item = CartItem(cart_id=cart.id, product_id=product_id, quantity=1) db.session.add(cart_item) db.session.commit() flash(f"Added {product.name} to cart!", "success") referrer = request.referrer if referrer and ('/product/' in referrer or '/products' in referrer): return redirect(referrer) return redirect(url_for('main.products')) @cart_bp.route('/remove/', methods=['POST']) @login_required def remove_from_cart(item_id): cart_item = CartItem.query.get_or_404(item_id) if cart_item.cart.user_id != current_user.id: flash("You don't have permission to remove this item", "danger") return redirect(url_for('cart.view_cart')) product_name = cart_item.product.name db.session.delete(cart_item) db.session.commit() flash(f"{product_name} removed from cart", "info") return redirect(url_for('cart.view_cart')) @cart_bp.route('/update/', methods=['POST']) @login_required def update_cart(item_id): cart_item = CartItem.query.get_or_404(item_id) if cart_item.cart.user_id != current_user.id: flash("You don't have permission to update this item", "danger") return redirect(url_for('cart.view_cart')) new_quantity = request.form.get('quantity') product = Product.query.get(cart_item.product_id) try: new_quantity = int(new_quantity) if new_quantity > 0: if new_quantity > product.stock: flash( f"Only {product.stock} items available in stock. Quantity adjusted.", "warning") new_quantity = product.stock cart_item.quantity = new_quantity db.session.commit() flash("Cart updated", "success") elif new_quantity == 0: db.session.delete(cart_item) db.session.commit() flash("Item removed from cart", "info") else: flash("Quantity must be at least 0", "danger") except ValueError: flash("Invalid quantity", "danger") return redirect(url_for('cart.view_cart')) @cart_bp.route('/clear', methods=['POST']) @login_required def clear_cart(): cart = Cart.query.filter_by(user_id=current_user.id).first() if cart: items = cart.items if items: item_count = len(items) CartItem.query.filter_by(cart_id=cart.id).delete() db.session.commit() flash(f"Cart cleared ({item_count} items removed)", "info") else: flash("Your cart is already empty", "info") return redirect(url_for('cart.view_cart')) @cart_bp.route('/checkout', methods=['GET', 'POST']) @login_required def checkout(): cart = Cart.query.filter_by(user_id=current_user.id).first() if not cart or not cart.items: flash("Your cart is empty", "warning") return redirect(url_for('cart.view_cart')) for item in cart.items: product = Product.query.get(item.product_id) if product.stock < item.quantity: flash( f"Sorry, {product.name} only has {product.stock} items in stock (you have {item.quantity} in cart)", "danger") return redirect(url_for('cart.view_cart')) if request.method == 'POST': try: total = 0 order_items = [] for item in cart.items: product = Product.query.get(item.product_id) product.stock -= item.quantity total += product.price * item.quantity order_items.append({ 'product_id': product.id, 'quantity': item.quantity, 'price': product.price }) from models import Order, OrderItem from datetime import datetime order = Order(user_id=current_user.id, created_at=datetime.utcnow()) db.session.add(order) db.session.flush() for item_data in order_items: order_item = OrderItem( order_id=order.id, product_id=item_data['product_id'], quantity=item_data['quantity'] ) db.session.add(order_item) CartItem.query.filter_by(cart_id=cart.id).delete() db.session.commit() flash(f"Order placed successfully! Total: ${total:.2f}", "success") return redirect(url_for('user.profile')) except Exception as e: db.session.rollback() flash(f"Checkout failed: {str(e)}", "danger") return redirect(url_for('cart.view_cart')) total = sum(item.product.price * item.quantity for item in cart.items) return render_template('checkout.html', cart=cart, total=total) @cart_bp.route('/count') @login_required def cart_count(): cart = Cart.query.filter_by(user_id=current_user.id).first() if cart: count = sum(item.quantity for item in cart.items) else: count = 0 return str(count)