Files
mealno-backend/models.py
T
2026-05-25 14:07:00 +00:00

405 lines
12 KiB
Python

from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey, DateTime, Text
from sqlalchemy.orm import relationship
from datetime import datetime
from sqlalchemy import Index
from database import Base
# =========================
# USER
# =========================
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=True)
phone = Column(String, unique=True, nullable=False)
email = Column(String, unique=True)
# 🔥 ADD THESE TWO NEW COLUMNS
dob = Column(String, nullable=True)
gender = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
orders = relationship("Order", back_populates="user")
# 🔥 NEW RELATION
addresses = relationship("UserAddress", back_populates="user")
class UserAddress(Base):
__tablename__ = "user_addresses"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"), index=True)
flat = Column(String)
building = Column(String)
landmark = Column(String)
lat = Column(Float)
lng = Column(Float)
address_type = Column(String) # HOME / WORK / OTHER
is_default = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
user = relationship("User", back_populates="addresses")
# =========================
# VENDOR (Kitchen)
# =========================
class Vendor(Base):
__tablename__ = "vendors"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
# 🔥 FULL ADDRESS (structured)
flat = Column(String)
building = Column(String)
landmark = Column(String)
location = Column(String) # full readable address
lat = Column(Float, nullable=False)
lng = Column(Float, nullable=False)
radius = Column(Float, default=2)
email = Column(String, unique=True)
password = Column(String)
is_active = Column(Boolean, default=True)
is_open = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
city = Column(String)
zone = Column(String)
zonal_admin_id = Column(Integer, ForeignKey("admins.id"))
menus = relationship("VendorMenu", back_populates="vendor")
# =========================
# MENU ITEMS (Admin Controlled)
# =========================
class MenuItem(Base):
__tablename__ = "menu_items"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
category = Column(String)
description = Column(Text) # 🔥 NEW
vendor_price = Column(Float, nullable=False)
selling_price = Column(Float, nullable=False)
image_url = Column(String, nullable=True)
is_deleted = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow)
vendors = relationship("VendorMenu", back_populates="menu_item")
# =========================
# VENDOR MENU (Availability)
# =========================
class VendorMenu(Base):
__tablename__ = "vendor_menu"
id = Column(Integer, primary_key=True, index=True)
vendor_id = Column(Integer, ForeignKey("vendors.id"), index=True)
menu_item_id = Column(Integer, ForeignKey("menu_items.id"), index=True)
is_available = Column(Boolean, default=True)
vendor = relationship("Vendor", back_populates="menus")
menu_item = relationship("MenuItem", back_populates="vendors")
# =========================
# ORDER
# =========================
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True, index=True)
batch_id = Column(Integer, ForeignKey("batches.id"), nullable=True, index=True)
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True) # ✅ ADD
admin = relationship("Admin")
user_id = Column(Integer, ForeignKey("users.id"), index=True)
user_lat = Column(Float)
user_lng = Column(Float)
# 🔥 ORDER ADDRESS SNAPSHOT
address_flat = Column(String, nullable=True)
address_building = Column(String, nullable=True)
address_landmark = Column(String, nullable=True)
address_type = Column(String, nullable=True)
address_lat = Column(Float, nullable=True)
address_lng = Column(Float, nullable=True)
total_amount = Column(Float, nullable=False)
gst = Column(Float, nullable=False)
final_amount = Column(Float, nullable=False)
status = Column(String, default="PLACED", index=True)
reject_reason = Column(String, nullable=True) # 🔥 ADD THIS
payment_status = Column(String, default="PENDING")
delivery = relationship("Delivery", back_populates="order", uselist=False)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
user = relationship("User", back_populates="orders")
items = relationship("OrderItem", back_populates="order")
batch = relationship("Batch", back_populates="orders")
cancel_reason = Column(Text, nullable=True)
cancelled_by = Column(String, nullable=True)
cancelled_at = Column(DateTime, nullable=True)
# =========================
# ORDER ITEMS (Snapshot)
# =========================
class OrderItem(Base):
__tablename__ = "order_items"
id = Column(Integer, primary_key=True, index=True)
order_id = Column(Integer, ForeignKey("orders.id"), index=True)
menu_item_id = Column(Integer, ForeignKey("menu_items.id"), index=True)
vendor_id = Column(Integer, index=True)
quantity = Column(Integer, nullable=False)
name = Column(String)
vendor_price = Column(Float, nullable=False)
selling_price = Column(Float, nullable=False)
status = Column(String, default="PREPARING")
order = relationship("Order", back_populates="items")
# ✅ MUST BE INSIDE CLASS
__table_args__ = (
Index("idx_order_vendor", "order_id", "vendor_id"),
)
# =========================
# DELIVERY
# =========================
class Delivery(Base):
__tablename__ = "deliveries"
id = Column(Integer, primary_key=True, index=True)
order_id = Column(Integer, ForeignKey("orders.id"), index=True)
delivery_boy_id = Column(Integer, ForeignKey("delivery_boys.id"), index=True)
status = Column(String, default="ASSIGNED")
# Payment handling
payment_method = Column(String) # COD / QR
payment_amount = Column(Float) # ✅ store actual paid amount
payment_proof = Column(Text) # image URL / text note
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
delivery_boy = relationship("DeliveryBoy")
order = relationship("Order", back_populates="delivery")
class Batch(Base):
__tablename__ = "batches"
id = Column(Integer, primary_key=True, index=True)
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True) # ✅ ADD
status = Column(String, default="CREATED", index=True)
# CREATED / ASSIGNED / PICKED_UP / OUT_FOR_DELIVERY / DELIVERED # CREATED / ASSIGNED / PICKED / COMPLETED
created_at = Column(DateTime, default=datetime.utcnow)
delivery_boy_id = Column(Integer, ForeignKey("delivery_boys.id"), nullable=True)
orders = relationship("Order", back_populates="batch")
# ✅ FIX HERE
delivery_boy = relationship(
"DeliveryBoy",
back_populates="batches",
foreign_keys=[delivery_boy_id]
)
# =========================
# ADMIN (City + Zonal)
# =========================
class Admin(Base):
__tablename__ = "admins"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, nullable=False)
password = Column(String, nullable=False)
role = Column(String, nullable=False)
# CITY_ADMIN / ZONAL_ADMIN
city = Column(String, nullable=True)
zone = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
class DeliveryBoy(Base):
__tablename__ = "delivery_boys"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, nullable=False)
phone = Column(String, nullable=False)
password = Column(String, nullable=False)
city = Column(String)
zone = Column(String)
zonal_admin_id = Column(Integer, ForeignKey("admins.id"))
is_active = Column(Boolean, default=True)
# 🔥 NEW: STATUS SYSTEM
status = Column(String, default="OFFLINE", index=True)
# OFFLINE / IDLE / ASSIGNED / PICKED_UP / OUT_FOR_DELIVERY
# 🔥 NEW: ASSIGNMENT TRACKING (VERY IMPORTANT)
current_batch_id = Column(Integer, nullable=True)
current_order_id = Column(Integer, nullable=True)
# 🔥 NEW: LIVE LOCATION (for admin tracking later)
lat = Column(Float, nullable=True)
lng = Column(Float, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
# ✅ ADD THIS (CRITICAL FIX)
batches = relationship(
"Batch",
back_populates="delivery_boy",
foreign_keys="Batch.delivery_boy_id"
)
from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean
from datetime import datetime
class NotificationToken(Base):
__tablename__ = "notification_tokens"
id = Column(
Integer,
primary_key=True,
index=True
)
user_id = Column(
Integer,
nullable=False,
index=True
)
role = Column(
String,
nullable=False
)
token = Column(
Text,
unique=True,
nullable=False
)
# ✅ DEVICE INFO
device_name = Column(String)
platform = Column(String)
browser = Column(String)
# ✅ ACTIVE / LOGOUT SUPPORT
is_active = Column(
Boolean,
default=True
)
created_at = Column(
DateTime,
default=datetime.utcnow
)
updated_at = Column(
DateTime,
default=datetime.utcnow,
onupdate=datetime.utcnow
)
# =========================
# REVIEWS
# =========================
class Review(Base):
__tablename__ = "reviews"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"), index=True)
order_id = Column(Integer, ForeignKey("orders.id"), unique=True, index=True) # One review per order
zonal_admin_id = Column(Integer, ForeignKey("admins.id"), index=True)
rating = Column(Integer, nullable=False) # 1 to 5 stars
comment = Column(Text, nullable=True) # Optional written review
created_at = Column(DateTime, default=datetime.utcnow)
# Relationships
user = relationship("User")
order = relationship("Order")
zonal_admin = relationship("Admin")
# =========================
# SUPPORT TICKETS
# =========================
class SupportTicket(Base):
__tablename__ = "support_tickets"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"))
user_name = Column(String, nullable=False)
mobile_number = Column(String, nullable=False)
message = Column(Text, nullable=False)
status = Column(String, default="OPEN")
# OPEN / CLOSED / IN_PROGRESS
created_at = Column(DateTime, default=datetime.utcnow)
frontend_ip = Column(String, nullable=True)
backend_ip = Column(String, nullable=True)
user = relationship("User")