197 lines
6.5 KiB
Python
197 lines
6.5 KiB
Python
|
|
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'<Product {self.name}>'
|
|
|
|
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')
|
|
|