import os from datetime import datetime from flask_login import UserMixin from werkzeug.security import check_password_hash, generate_password_hash from extensions import db class SizeEnum: XS = 'XS' S = 'S' M = 'M' L = 'L' XL = 'XL' XXL = 'XXL' XXXL = 'XXXL' ALL = [XS, S, M, L, XL, XXL, XXXL] class CategoryEnum: T_SHIRTS = 'T-Shirts' SHIRTS = 'Shirts' JEANS = 'Jeans' PANTS = 'Pants' JACKETS = 'Jackets' HOODIES = 'Hoodies' SWEATERS = 'Sweaters' SHORTS = 'Shorts' DRESSES = 'Dresses' SKIRTS = 'Skirts' ACTIVEWEAR = 'Activewear' SHOES = 'Shoes' ACCESSORIES = 'Accessories' ALL = [ T_SHIRTS, SHIRTS, JEANS, PANTS, JACKETS, HOODIES, SWEATERS, SHORTS, DRESSES, SKIRTS, ACTIVEWEAR, SHOES, ACCESSORIES ] class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(120), unique=True, nullable=False) password_hash = db.Column(db.String(255)) is_admin = db.Column(db.Boolean, default=False) cart = db.relationship('Cart', backref='user', uselist=False) orders = db.relationship('Order', backref='user', lazy=True) reviews = db.relationship('Review', backref='user', lazy=True) likes = db.relationship('ProductLike', backref='user', lazy=True) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) class Category(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False) products = db.relationship('Product', backref='category', lazy=True) class Product(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(120), nullable=False) description = db.Column(db.Text) price = db.Column(db.Float, nullable=False) stock = db.Column(db.Integer, default=0) color = db.Column(db.String(50)) size = db.Column(db.String(10)) material = db.Column(db.String(50)) company = db.Column(db.String(100)) sku = db.Column(db.String(50), unique=True) weight = db.Column(db.Float) dimensions = db.Column(db.String(50)) category_id = db.Column(db.Integer, db.ForeignKey('category.id')) images = db.relationship( 'ProductImage', backref='product', lazy=True, cascade="all, delete-orphan") reviews = db.relationship('Review', backref='product', lazy=True, cascade="all, delete-orphan") likes = db.relationship('ProductLike', backref='product', lazy=True, cascade="all, delete-orphan") @property def average_rating(self): if not self.reviews: return 0 total = sum(review.rating for review in self.reviews) return round(total / len(self.reviews), 1) @property def like_count(self): return len([like for like in self.likes if like.is_like]) @property def dislike_count(self): return len([like for like in self.likes if not like.is_like]) @property def review_count(self): return len(self.reviews) @property def primary_image(self): if self.images: primary = next((img for img in self.images if img.is_primary), None) if primary: return primary return self.images[0] return None def get_image_url(self): """Alias for template compatibility""" return self.get_primary_image_url() def in_stock(self): return self.stock > 0 def get_primary_image_url(self): primary = self.primary_image if primary: return f"/static/uploads/products/{primary.filename}" return "/static/images/default-product.jpg" def get_all_image_urls(self): return [f"/static/uploads/products/{img.filename}" for img in self.images] def __repr__(self): return f'' class ProductImage(db.Model): id = db.Column(db.Integer, primary_key=True) product_id = db.Column( db.Integer, db.ForeignKey('product.id'), nullable=False) filename = db.Column(db.String(200), nullable=False) is_primary = db.Column(db.Boolean, default=False) display_order = db.Column(db.Integer, default=0) created_at = db.Column(db.DateTime, default=datetime.utcnow) class ProductLike(db.Model): id = db.Column(db.Integer, primary_key=True) product_id = db.Column( db.Integer, db.ForeignKey('product.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) is_like = db.Column(db.Boolean, default=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) __table_args__ = (db.UniqueConstraint( 'product_id', 'user_id', name='unique_product_user_like'),) class Review(db.Model): id = db.Column(db.Integer, primary_key=True) product_id = db.Column( db.Integer, db.ForeignKey('product.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) rating = db.Column(db.Integer, nullable=False) title = db.Column(db.String(200)) comment = db.Column(db.Text) is_verified_purchase = db.Column(db.Boolean, default=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, onupdate=datetime.utcnow) class Cart(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) items = db.relationship('CartItem', backref='cart', cascade="all, delete-orphan", lazy=True) class CartItem(db.Model): id = db.Column(db.Integer, primary_key=True) cart_id = db.Column(db.Integer, db.ForeignKey('cart.id')) product_id = db.Column(db.Integer, db.ForeignKey('product.id')) quantity = db.Column(db.Integer, default=1) selected_size = db.Column(db.String(10)) selected_color = db.Column(db.String(50)) product = db.relationship('Product') class Order(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) created_at = db.Column(db.DateTime, default=datetime.utcnow) status = db.Column(db.String(50), default='pending') items = db.relationship('OrderItem', backref='order', cascade='all, delete-orphan', lazy=True) class OrderItem(db.Model): id = db.Column(db.Integer, primary_key=True) order_id = db.Column(db.Integer, db.ForeignKey('order.id')) product_id = db.Column(db.Integer, db.ForeignKey('product.id')) quantity = db.Column(db.Integer, default=1) price_at_purchase = db.Column(db.Float) selected_size = db.Column(db.String(10)) selected_color = db.Column(db.String(50)) product = db.relationship('Product')