updates
This commit is contained in:
@@ -20,36 +20,5 @@ from .cookie_integration_config import CookieIntegrationConfig
|
||||
from .system_settings import SystemSettings
|
||||
from .invoice import Invoice, InvoiceItem
|
||||
from .page_content import PageContent, PageType
|
||||
|
||||
__all__ = [
|
||||
"Role",
|
||||
"User",
|
||||
"RefreshToken",
|
||||
"PasswordResetToken",
|
||||
"RoomType",
|
||||
"Room",
|
||||
"Booking",
|
||||
"Payment",
|
||||
"Service",
|
||||
"ServiceUsage",
|
||||
"ServiceBooking",
|
||||
"ServiceBookingItem",
|
||||
"ServicePayment",
|
||||
"ServiceBookingStatus",
|
||||
"ServicePaymentStatus",
|
||||
"ServicePaymentMethod",
|
||||
"Promotion",
|
||||
"CheckInCheckOut",
|
||||
"Banner",
|
||||
"Review",
|
||||
"Favorite",
|
||||
"AuditLog",
|
||||
"CookiePolicy",
|
||||
"CookieIntegrationConfig",
|
||||
"SystemSettings",
|
||||
"Invoice",
|
||||
"InvoiceItem",
|
||||
"PageContent",
|
||||
"PageType",
|
||||
]
|
||||
|
||||
from .chat import Chat, ChatMessage, ChatStatus
|
||||
__all__ = ['Role', 'User', 'RefreshToken', 'PasswordResetToken', 'RoomType', 'Room', 'Booking', 'Payment', 'Service', 'ServiceUsage', 'ServiceBooking', 'ServiceBookingItem', 'ServicePayment', 'ServiceBookingStatus', 'ServicePaymentStatus', 'ServicePaymentMethod', 'Promotion', 'CheckInCheckOut', 'Banner', 'Review', 'Favorite', 'AuditLog', 'CookiePolicy', 'CookieIntegrationConfig', 'SystemSettings', 'Invoice', 'InvoiceItem', 'PageContent', 'PageType', 'Chat', 'ChatMessage', 'ChatStatus']
|
||||
Binary file not shown.
BIN
Backend/src/models/__pycache__/chat.cpython-312.pyc
Normal file
BIN
Backend/src/models/__pycache__/chat.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,28 +1,20 @@
|
||||
"""
|
||||
Audit log model for tracking important actions
|
||||
"""
|
||||
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class AuditLog(Base):
|
||||
__tablename__ = "audit_logs"
|
||||
|
||||
__tablename__ = 'audit_logs'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=True, index=True)
|
||||
action = Column(String(100), nullable=False, index=True) # e.g., "user.created", "booking.cancelled"
|
||||
resource_type = Column(String(50), nullable=False, index=True) # e.g., "user", "booking"
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=True, index=True)
|
||||
action = Column(String(100), nullable=False, index=True)
|
||||
resource_type = Column(String(50), nullable=False, index=True)
|
||||
resource_id = Column(Integer, nullable=True, index=True)
|
||||
ip_address = Column(String(45), nullable=True) # IPv6 compatible
|
||||
ip_address = Column(String(45), nullable=True)
|
||||
user_agent = Column(String(255), nullable=True)
|
||||
request_id = Column(String(36), nullable=True, index=True) # UUID
|
||||
details = Column(JSON, nullable=True) # Additional context
|
||||
status = Column(String(20), nullable=False, default="success") # success, failed, error
|
||||
request_id = Column(String(36), nullable=True, index=True)
|
||||
details = Column(JSON, nullable=True)
|
||||
status = Column(String(20), nullable=False, default='success')
|
||||
error_message = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", foreign_keys=[user_id])
|
||||
|
||||
user = relationship('User', foreign_keys=[user_id])
|
||||
@@ -3,16 +3,14 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class Banner(Base):
|
||||
__tablename__ = "banners"
|
||||
|
||||
__tablename__ = 'banners'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
title = Column(String(100), nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
image_url = Column(String(255), nullable=False)
|
||||
link_url = Column(String(255), nullable=True)
|
||||
position = Column(String(50), nullable=False, default="home")
|
||||
position = Column(String(50), nullable=False, default='home')
|
||||
display_order = Column(Integer, nullable=False, default=0)
|
||||
is_active = Column(Boolean, nullable=False, default=True)
|
||||
start_date = Column(DateTime, nullable=True)
|
||||
@@ -27,5 +25,4 @@ class Banner(Base):
|
||||
return False
|
||||
if not self.start_date or not self.end_date:
|
||||
return self.is_active
|
||||
return self.start_date <= now <= self.end_date
|
||||
|
||||
return self.start_date <= now <= self.end_date
|
||||
@@ -4,41 +4,35 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class BookingStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
confirmed = "confirmed"
|
||||
checked_in = "checked_in"
|
||||
checked_out = "checked_out"
|
||||
cancelled = "cancelled"
|
||||
|
||||
pending = 'pending'
|
||||
confirmed = 'confirmed'
|
||||
checked_in = 'checked_in'
|
||||
checked_out = 'checked_out'
|
||||
cancelled = 'cancelled'
|
||||
|
||||
class Booking(Base):
|
||||
__tablename__ = "bookings"
|
||||
|
||||
__tablename__ = 'bookings'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
booking_number = Column(String(50), unique=True, nullable=False, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey("rooms.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey('rooms.id'), nullable=False)
|
||||
check_in_date = Column(DateTime, nullable=False)
|
||||
check_out_date = Column(DateTime, nullable=False)
|
||||
num_guests = Column(Integer, nullable=False, default=1)
|
||||
total_price = Column(Numeric(10, 2), nullable=False)
|
||||
original_price = Column(Numeric(10, 2), nullable=True) # Price before discount
|
||||
discount_amount = Column(Numeric(10, 2), nullable=True, default=0) # Discount amount applied
|
||||
promotion_code = Column(String(50), nullable=True) # Promotion code used
|
||||
original_price = Column(Numeric(10, 2), nullable=True)
|
||||
discount_amount = Column(Numeric(10, 2), nullable=True, default=0)
|
||||
promotion_code = Column(String(50), nullable=True)
|
||||
status = Column(Enum(BookingStatus), nullable=False, default=BookingStatus.pending)
|
||||
deposit_paid = Column(Boolean, nullable=False, default=False)
|
||||
requires_deposit = Column(Boolean, nullable=False, default=False)
|
||||
special_requests = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="bookings")
|
||||
room = relationship("Room", back_populates="bookings")
|
||||
payments = relationship("Payment", back_populates="booking", cascade="all, delete-orphan")
|
||||
invoices = relationship("Invoice", back_populates="booking", cascade="all, delete-orphan")
|
||||
service_usages = relationship("ServiceUsage", back_populates="booking", cascade="all, delete-orphan")
|
||||
checkin_checkout = relationship("CheckInCheckOut", back_populates="booking", uselist=False)
|
||||
|
||||
user = relationship('User', back_populates='bookings')
|
||||
room = relationship('Room', back_populates='bookings')
|
||||
payments = relationship('Payment', back_populates='booking', cascade='all, delete-orphan')
|
||||
invoices = relationship('Invoice', back_populates='booking', cascade='all, delete-orphan')
|
||||
service_usages = relationship('ServiceUsage', back_populates='booking', cascade='all, delete-orphan')
|
||||
checkin_checkout = relationship('CheckInCheckOut', back_populates='booking', uselist=False)
|
||||
37
Backend/src/models/chat.py
Normal file
37
Backend/src/models/chat.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, Enum, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
class ChatStatus(str, enum.Enum):
|
||||
pending = 'pending'
|
||||
active = 'active'
|
||||
closed = 'closed'
|
||||
|
||||
class Chat(Base):
|
||||
__tablename__ = 'chats'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
visitor_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
visitor_name = Column(String(100), nullable=True)
|
||||
visitor_email = Column(String(100), nullable=True)
|
||||
staff_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
status = Column(Enum(ChatStatus), nullable=False, default=ChatStatus.pending)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
closed_at = Column(DateTime, nullable=True)
|
||||
visitor = relationship('User', foreign_keys=[visitor_id], back_populates='visitor_chats')
|
||||
staff = relationship('User', foreign_keys=[staff_id], back_populates='staff_chats')
|
||||
messages = relationship('ChatMessage', back_populates='chat', cascade='all, delete-orphan', order_by='ChatMessage.created_at')
|
||||
|
||||
class ChatMessage(Base):
|
||||
__tablename__ = 'chat_messages'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
chat_id = Column(Integer, ForeignKey('chats.id'), nullable=False)
|
||||
sender_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
sender_type = Column(String(20), nullable=False)
|
||||
message = Column(Text, nullable=False)
|
||||
is_read = Column(Boolean, nullable=False, default=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
chat = relationship('Chat', back_populates='messages')
|
||||
sender = relationship('User', foreign_keys=[sender_id])
|
||||
@@ -3,25 +3,20 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class CheckInCheckOut(Base):
|
||||
__tablename__ = "checkin_checkout"
|
||||
|
||||
__tablename__ = 'checkin_checkout'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
booking_id = Column(Integer, ForeignKey("bookings.id"), nullable=False, unique=True)
|
||||
booking_id = Column(Integer, ForeignKey('bookings.id'), nullable=False, unique=True)
|
||||
checkin_time = Column(DateTime, nullable=True)
|
||||
checkout_time = Column(DateTime, nullable=True)
|
||||
checkin_by = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
checkout_by = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
checkin_by = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
checkout_by = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
room_condition_checkin = Column(Text, nullable=True)
|
||||
room_condition_checkout = Column(Text, nullable=True)
|
||||
additional_charges = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
booking = relationship("Booking", back_populates="checkin_checkout")
|
||||
checked_in_by = relationship("User", foreign_keys=[checkin_by], back_populates="checkins_processed")
|
||||
checked_out_by = relationship("User", foreign_keys=[checkout_by], back_populates="checkouts_processed")
|
||||
|
||||
booking = relationship('Booking', back_populates='checkin_checkout')
|
||||
checked_in_by = relationship('User', foreign_keys=[checkin_by], back_populates='checkins_processed')
|
||||
checked_out_by = relationship('User', foreign_keys=[checkout_by], back_populates='checkouts_processed')
|
||||
@@ -1,30 +1,14 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class CookieIntegrationConfig(Base):
|
||||
"""
|
||||
Stores IDs for well-known integrations (e.g., Google Analytics, Meta Pixel).
|
||||
Does NOT allow arbitrary script injection from the dashboard.
|
||||
"""
|
||||
|
||||
__tablename__ = "cookie_integration_configs"
|
||||
|
||||
__tablename__ = 'cookie_integration_configs'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
|
||||
ga_measurement_id = Column(String(64), nullable=True) # e.g. G-XXXXXXXXXX
|
||||
fb_pixel_id = Column(String(64), nullable=True) # e.g. 1234567890
|
||||
|
||||
ga_measurement_id = Column(String(64), nullable=True)
|
||||
fb_pixel_id = Column(String(64), nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(
|
||||
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False
|
||||
)
|
||||
|
||||
updated_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = relationship("User", lazy="joined")
|
||||
|
||||
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
updated_by_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
updated_by = relationship('User', lazy='joined')
|
||||
@@ -1,31 +1,15 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class CookiePolicy(Base):
|
||||
"""
|
||||
Global cookie policy controlled by administrators.
|
||||
|
||||
This does NOT store per-user consent; it controls which cookie categories
|
||||
are available to be requested from users (e.g., disable analytics entirely).
|
||||
"""
|
||||
|
||||
__tablename__ = "cookie_policies"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
|
||||
analytics_enabled = Column(Boolean, default=True, nullable=False)
|
||||
marketing_enabled = Column(Boolean, default=True, nullable=False)
|
||||
preferences_enabled = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
updated_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = relationship("User", lazy="joined")
|
||||
|
||||
|
||||
__tablename__ = 'cookie_policies'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
analytics_enabled = Column(Boolean, default=True, nullable=False)
|
||||
marketing_enabled = Column(Boolean, default=True, nullable=False)
|
||||
preferences_enabled = Column(Boolean, default=True, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
updated_by_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
updated_by = relationship('User', lazy='joined')
|
||||
@@ -3,17 +3,12 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class Favorite(Base):
|
||||
__tablename__ = "favorites"
|
||||
|
||||
__tablename__ = 'favorites'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey("rooms.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey('rooms.id'), nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="favorites")
|
||||
room = relationship("Room", back_populates="favorites")
|
||||
|
||||
user = relationship('User', back_populates='favorites')
|
||||
room = relationship('Room', back_populates='favorites')
|
||||
@@ -4,98 +4,68 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class InvoiceStatus(str, enum.Enum):
|
||||
draft = "draft"
|
||||
sent = "sent"
|
||||
paid = "paid"
|
||||
overdue = "overdue"
|
||||
cancelled = "cancelled"
|
||||
|
||||
draft = 'draft'
|
||||
sent = 'sent'
|
||||
paid = 'paid'
|
||||
overdue = 'overdue'
|
||||
cancelled = 'cancelled'
|
||||
|
||||
class Invoice(Base):
|
||||
__tablename__ = "invoices"
|
||||
|
||||
__tablename__ = 'invoices'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
invoice_number = Column(String(50), unique=True, nullable=False, index=True)
|
||||
booking_id = Column(Integer, ForeignKey("bookings.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
|
||||
# Invoice details
|
||||
booking_id = Column(Integer, ForeignKey('bookings.id'), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
issue_date = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
due_date = Column(DateTime, nullable=False)
|
||||
paid_date = Column(DateTime, nullable=True)
|
||||
|
||||
# Amounts
|
||||
subtotal = Column(Numeric(10, 2), nullable=False, default=0.00)
|
||||
tax_rate = Column(Numeric(5, 2), nullable=False, default=0.00) # Tax percentage
|
||||
tax_amount = Column(Numeric(10, 2), nullable=False, default=0.00)
|
||||
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.00)
|
||||
subtotal = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
tax_rate = Column(Numeric(5, 2), nullable=False, default=0.0)
|
||||
tax_amount = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
total_amount = Column(Numeric(10, 2), nullable=False)
|
||||
amount_paid = Column(Numeric(10, 2), nullable=False, default=0.00)
|
||||
amount_paid = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
balance_due = Column(Numeric(10, 2), nullable=False)
|
||||
|
||||
# Status
|
||||
status = Column(Enum(InvoiceStatus), nullable=False, default=InvoiceStatus.draft)
|
||||
is_proforma = Column(Boolean, nullable=False, default=False) # True for proforma invoices
|
||||
|
||||
# Company/Organization information (for admin to manage)
|
||||
is_proforma = Column(Boolean, nullable=False, default=False)
|
||||
company_name = Column(String(200), nullable=True)
|
||||
company_address = Column(Text, nullable=True)
|
||||
company_phone = Column(String(50), nullable=True)
|
||||
company_email = Column(String(100), nullable=True)
|
||||
company_tax_id = Column(String(100), nullable=True)
|
||||
company_logo_url = Column(String(500), nullable=True)
|
||||
|
||||
# Customer information (snapshot at invoice creation)
|
||||
customer_name = Column(String(200), nullable=False)
|
||||
customer_email = Column(String(100), nullable=False)
|
||||
customer_address = Column(Text, nullable=True)
|
||||
customer_phone = Column(String(50), nullable=True)
|
||||
customer_tax_id = Column(String(100), nullable=True)
|
||||
|
||||
# Additional information
|
||||
notes = Column(Text, nullable=True)
|
||||
terms_and_conditions = Column(Text, nullable=True)
|
||||
payment_instructions = Column(Text, nullable=True)
|
||||
|
||||
# Metadata
|
||||
created_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
updated_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
created_by_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
updated_by_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
booking = relationship("Booking", back_populates="invoices")
|
||||
user = relationship("User", foreign_keys=[user_id], backref="invoices")
|
||||
created_by = relationship("User", foreign_keys=[created_by_id])
|
||||
updated_by = relationship("User", foreign_keys=[updated_by_id])
|
||||
items = relationship("InvoiceItem", back_populates="invoice", cascade="all, delete-orphan")
|
||||
|
||||
booking = relationship('Booking', back_populates='invoices')
|
||||
user = relationship('User', foreign_keys=[user_id], backref='invoices')
|
||||
created_by = relationship('User', foreign_keys=[created_by_id])
|
||||
updated_by = relationship('User', foreign_keys=[updated_by_id])
|
||||
items = relationship('InvoiceItem', back_populates='invoice', cascade='all, delete-orphan')
|
||||
|
||||
class InvoiceItem(Base):
|
||||
__tablename__ = "invoice_items"
|
||||
|
||||
__tablename__ = 'invoice_items'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
invoice_id = Column(Integer, ForeignKey("invoices.id"), nullable=False)
|
||||
|
||||
# Item details
|
||||
invoice_id = Column(Integer, ForeignKey('invoices.id'), nullable=False)
|
||||
description = Column(String(500), nullable=False)
|
||||
quantity = Column(Numeric(10, 2), nullable=False, default=1.00)
|
||||
quantity = Column(Numeric(10, 2), nullable=False, default=1.0)
|
||||
unit_price = Column(Numeric(10, 2), nullable=False)
|
||||
tax_rate = Column(Numeric(5, 2), nullable=False, default=0.00)
|
||||
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.00)
|
||||
tax_rate = Column(Numeric(5, 2), nullable=False, default=0.0)
|
||||
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.0)
|
||||
line_total = Column(Numeric(10, 2), nullable=False)
|
||||
|
||||
# Optional reference to booking items
|
||||
room_id = Column(Integer, ForeignKey("rooms.id"), nullable=True)
|
||||
service_id = Column(Integer, ForeignKey("services.id"), nullable=True)
|
||||
|
||||
# Metadata
|
||||
room_id = Column(Integer, ForeignKey('rooms.id'), nullable=True)
|
||||
service_id = Column(Integer, ForeignKey('services.id'), nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
invoice = relationship("Invoice", back_populates="items")
|
||||
room = relationship("Room")
|
||||
service = relationship("Service")
|
||||
|
||||
invoice = relationship('Invoice', back_populates='items')
|
||||
room = relationship('Room')
|
||||
service = relationship('Service')
|
||||
@@ -2,31 +2,23 @@ from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Enum as
|
||||
from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
import enum
|
||||
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class PageType(str, enum.Enum):
|
||||
HOME = "home"
|
||||
CONTACT = "contact"
|
||||
ABOUT = "about"
|
||||
FOOTER = "footer"
|
||||
SEO = "seo"
|
||||
|
||||
HOME = 'home'
|
||||
CONTACT = 'contact'
|
||||
ABOUT = 'about'
|
||||
FOOTER = 'footer'
|
||||
SEO = 'seo'
|
||||
|
||||
class PageContent(Base):
|
||||
__tablename__ = "page_contents"
|
||||
|
||||
__tablename__ = 'page_contents'
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
page_type = Column(SQLEnum(PageType), nullable=False, unique=True, index=True)
|
||||
|
||||
# General content fields
|
||||
title = Column(String(500), nullable=True)
|
||||
subtitle = Column(String(1000), nullable=True)
|
||||
description = Column(Text, nullable=True)
|
||||
content = Column(Text, nullable=True) # Rich text content
|
||||
|
||||
# SEO fields
|
||||
content = Column(Text, nullable=True)
|
||||
meta_title = Column(String(500), nullable=True)
|
||||
meta_description = Column(Text, nullable=True)
|
||||
meta_keywords = Column(String(1000), nullable=True)
|
||||
@@ -34,67 +26,57 @@ class PageContent(Base):
|
||||
og_description = Column(Text, nullable=True)
|
||||
og_image = Column(String(1000), nullable=True)
|
||||
canonical_url = Column(String(1000), nullable=True)
|
||||
|
||||
# Contact/Footer specific fields (stored as JSON strings)
|
||||
contact_info = Column(Text, nullable=True) # JSON: phone, email, address
|
||||
map_url = Column(String(1000), nullable=True) # Google Maps embed URL
|
||||
social_links = Column(Text, nullable=True) # JSON: facebook, twitter, instagram, etc.
|
||||
footer_links = Column(Text, nullable=True) # JSON: quick links, support links
|
||||
badges = Column(Text, nullable=True) # JSON: array of badges with text and icon
|
||||
copyright_text = Column(Text, nullable=True) # Copyright text with {YEAR} placeholder for automatic year
|
||||
|
||||
# Home page specific
|
||||
contact_info = Column(Text, nullable=True)
|
||||
map_url = Column(String(1000), nullable=True)
|
||||
social_links = Column(Text, nullable=True)
|
||||
footer_links = Column(Text, nullable=True)
|
||||
badges = Column(Text, nullable=True)
|
||||
copyright_text = Column(Text, nullable=True)
|
||||
hero_title = Column(String(500), nullable=True)
|
||||
hero_subtitle = Column(String(1000), nullable=True)
|
||||
hero_image = Column(String(1000), nullable=True)
|
||||
|
||||
# About page specific
|
||||
story_content = Column(Text, nullable=True)
|
||||
values = Column(Text, nullable=True) # JSON array of values
|
||||
features = Column(Text, nullable=True) # JSON array of features
|
||||
about_hero_image = Column(Text, nullable=True) # Hero image for about page
|
||||
mission = Column(Text, nullable=True) # Mission statement
|
||||
vision = Column(Text, nullable=True) # Vision statement
|
||||
team = Column(Text, nullable=True) # JSON array of team members with name, role, image, bio, social_links
|
||||
timeline = Column(Text, nullable=True) # JSON array of timeline events with year, title, description, image
|
||||
achievements = Column(Text, nullable=True) # JSON array of achievements with icon, title, description, year, image
|
||||
|
||||
# Home page luxury sections
|
||||
values = Column(Text, nullable=True)
|
||||
features = Column(Text, nullable=True)
|
||||
about_hero_image = Column(Text, nullable=True)
|
||||
mission = Column(Text, nullable=True)
|
||||
vision = Column(Text, nullable=True)
|
||||
team = Column(Text, nullable=True)
|
||||
timeline = Column(Text, nullable=True)
|
||||
achievements = Column(Text, nullable=True)
|
||||
luxury_section_title = Column(Text, nullable=True)
|
||||
luxury_section_subtitle = Column(Text, nullable=True)
|
||||
luxury_section_image = Column(Text, nullable=True)
|
||||
luxury_features = Column(Text, nullable=True) # JSON array of features with icon, title, description
|
||||
luxury_features = Column(Text, nullable=True)
|
||||
luxury_gallery_section_title = Column(Text, nullable=True)
|
||||
luxury_gallery_section_subtitle = Column(Text, nullable=True)
|
||||
luxury_gallery = Column(Text, nullable=True) # JSON array of image URLs
|
||||
luxury_gallery = Column(Text, nullable=True)
|
||||
luxury_testimonials_section_title = Column(Text, nullable=True)
|
||||
luxury_testimonials_section_subtitle = Column(Text, nullable=True)
|
||||
luxury_testimonials = Column(Text, nullable=True) # JSON array of testimonials
|
||||
luxury_testimonials = Column(Text, nullable=True)
|
||||
amenities_section_title = Column(String(500), nullable=True)
|
||||
amenities_section_subtitle = Column(String(1000), nullable=True)
|
||||
amenities = Column(Text, nullable=True) # JSON array of amenities with icon, title, description, image
|
||||
amenities = Column(Text, nullable=True)
|
||||
testimonials_section_title = Column(String(500), nullable=True)
|
||||
testimonials_section_subtitle = Column(String(1000), nullable=True)
|
||||
testimonials = Column(Text, nullable=True) # JSON array of testimonials with name, role, image, rating, comment
|
||||
testimonials = Column(Text, nullable=True)
|
||||
gallery_section_title = Column(String(500), nullable=True)
|
||||
gallery_section_subtitle = Column(String(1000), nullable=True)
|
||||
gallery_images = Column(Text, nullable=True) # JSON array of image URLs
|
||||
gallery_images = Column(Text, nullable=True)
|
||||
about_preview_title = Column(String(500), nullable=True)
|
||||
about_preview_subtitle = Column(String(1000), nullable=True)
|
||||
about_preview_content = Column(Text, nullable=True)
|
||||
about_preview_image = Column(String(1000), nullable=True)
|
||||
stats = Column(Text, nullable=True) # JSON array of stats with number, label, icon
|
||||
|
||||
# Additional luxury sections
|
||||
stats = Column(Text, nullable=True)
|
||||
luxury_services_section_title = Column(Text, nullable=True)
|
||||
luxury_services_section_subtitle = Column(Text, nullable=True)
|
||||
luxury_services = Column(Text, nullable=True) # JSON array of services with icon, title, description, image
|
||||
luxury_services = Column(Text, nullable=True)
|
||||
luxury_experiences_section_title = Column(Text, nullable=True)
|
||||
luxury_experiences_section_subtitle = Column(Text, nullable=True)
|
||||
luxury_experiences = Column(Text, nullable=True) # JSON array of experiences with icon, title, description, image
|
||||
luxury_experiences = Column(Text, nullable=True)
|
||||
awards_section_title = Column(Text, nullable=True)
|
||||
awards_section_subtitle = Column(Text, nullable=True)
|
||||
awards = Column(Text, nullable=True) # JSON array of awards with icon, title, description, image, year
|
||||
awards = Column(Text, nullable=True)
|
||||
cta_title = Column(Text, nullable=True)
|
||||
cta_subtitle = Column(Text, nullable=True)
|
||||
cta_button_text = Column(Text, nullable=True)
|
||||
@@ -102,12 +84,7 @@ class PageContent(Base):
|
||||
cta_image = Column(Text, nullable=True)
|
||||
partners_section_title = Column(Text, nullable=True)
|
||||
partners_section_subtitle = Column(Text, nullable=True)
|
||||
partners = Column(Text, nullable=True) # JSON array of partners with name, logo, link
|
||||
|
||||
# Status
|
||||
partners = Column(Text, nullable=True)
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
@@ -3,18 +3,13 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class PasswordResetToken(Base):
|
||||
__tablename__ = "password_reset_tokens"
|
||||
|
||||
__tablename__ = 'password_reset_tokens'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
token = Column(String(255), unique=True, nullable=False, index=True)
|
||||
expires_at = Column(DateTime, nullable=False)
|
||||
used = Column(Boolean, default=False, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User")
|
||||
|
||||
user = relationship('User')
|
||||
@@ -4,48 +4,40 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class PaymentMethod(str, enum.Enum):
|
||||
cash = "cash"
|
||||
credit_card = "credit_card"
|
||||
debit_card = "debit_card"
|
||||
bank_transfer = "bank_transfer"
|
||||
e_wallet = "e_wallet"
|
||||
stripe = "stripe"
|
||||
paypal = "paypal"
|
||||
|
||||
cash = 'cash'
|
||||
credit_card = 'credit_card'
|
||||
debit_card = 'debit_card'
|
||||
bank_transfer = 'bank_transfer'
|
||||
e_wallet = 'e_wallet'
|
||||
stripe = 'stripe'
|
||||
paypal = 'paypal'
|
||||
|
||||
class PaymentType(str, enum.Enum):
|
||||
full = "full"
|
||||
deposit = "deposit"
|
||||
remaining = "remaining"
|
||||
|
||||
full = 'full'
|
||||
deposit = 'deposit'
|
||||
remaining = 'remaining'
|
||||
|
||||
class PaymentStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
completed = "completed"
|
||||
failed = "failed"
|
||||
refunded = "refunded"
|
||||
|
||||
pending = 'pending'
|
||||
completed = 'completed'
|
||||
failed = 'failed'
|
||||
refunded = 'refunded'
|
||||
|
||||
class Payment(Base):
|
||||
__tablename__ = "payments"
|
||||
|
||||
__tablename__ = 'payments'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
booking_id = Column(Integer, ForeignKey("bookings.id"), nullable=False)
|
||||
booking_id = Column(Integer, ForeignKey('bookings.id'), nullable=False)
|
||||
amount = Column(Numeric(10, 2), nullable=False)
|
||||
payment_method = Column(Enum(PaymentMethod), nullable=False)
|
||||
payment_type = Column(Enum(PaymentType), nullable=False, default=PaymentType.full)
|
||||
deposit_percentage = Column(Integer, nullable=True)
|
||||
related_payment_id = Column(Integer, ForeignKey("payments.id"), nullable=True)
|
||||
related_payment_id = Column(Integer, ForeignKey('payments.id'), nullable=True)
|
||||
payment_status = Column(Enum(PaymentStatus), nullable=False, default=PaymentStatus.pending)
|
||||
transaction_id = Column(String(100), nullable=True)
|
||||
payment_date = Column(DateTime, nullable=True)
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
booking = relationship("Booking", back_populates="payments")
|
||||
related_payment = relationship("Payment", remote_side=[id], backref="related_payments")
|
||||
|
||||
booking = relationship('Booking', back_populates='payments')
|
||||
related_payment = relationship('Payment', remote_side=[id], backref='related_payments')
|
||||
@@ -4,15 +4,12 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class DiscountType(str, enum.Enum):
|
||||
percentage = "percentage"
|
||||
fixed_amount = "fixed_amount"
|
||||
|
||||
percentage = 'percentage'
|
||||
fixed_amount = 'fixed_amount'
|
||||
|
||||
class Promotion(Base):
|
||||
__tablename__ = "promotions"
|
||||
|
||||
__tablename__ = 'promotions'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
code = Column(String(50), unique=True, nullable=False, index=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
@@ -43,18 +40,13 @@ class Promotion(Base):
|
||||
def calculate_discount(self, booking_amount):
|
||||
if not self.is_valid():
|
||||
return 0.0
|
||||
|
||||
if self.min_booking_amount and booking_amount < float(self.min_booking_amount):
|
||||
return 0.0
|
||||
|
||||
discount = 0.0
|
||||
if self.discount_type == DiscountType.percentage:
|
||||
discount = float(booking_amount) * float(self.discount_value) / 100.0
|
||||
elif self.discount_type == DiscountType.fixed_amount:
|
||||
discount = float(self.discount_value)
|
||||
|
||||
if self.max_discount_amount and discount > float(self.max_discount_amount):
|
||||
discount = float(self.max_discount_amount)
|
||||
|
||||
return discount
|
||||
|
||||
return discount
|
||||
@@ -3,16 +3,11 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class RefreshToken(Base):
|
||||
__tablename__ = "refresh_tokens"
|
||||
|
||||
__tablename__ = 'refresh_tokens'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
token = Column(String(500), unique=True, nullable=False, index=True)
|
||||
expires_at = Column(DateTime, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="refresh_tokens")
|
||||
|
||||
user = relationship('User', back_populates='refresh_tokens')
|
||||
@@ -4,26 +4,20 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class ReviewStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
approved = "approved"
|
||||
rejected = "rejected"
|
||||
|
||||
pending = 'pending'
|
||||
approved = 'approved'
|
||||
rejected = 'rejected'
|
||||
|
||||
class Review(Base):
|
||||
__tablename__ = "reviews"
|
||||
|
||||
__tablename__ = 'reviews'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey("rooms.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
room_id = Column(Integer, ForeignKey('rooms.id'), nullable=False)
|
||||
rating = Column(Integer, nullable=False)
|
||||
comment = Column(Text, nullable=False)
|
||||
status = Column(Enum(ReviewStatus), nullable=False, default=ReviewStatus.pending)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="reviews")
|
||||
room = relationship("Room", back_populates="reviews")
|
||||
|
||||
user = relationship('User', back_populates='reviews')
|
||||
room = relationship('Room', back_populates='reviews')
|
||||
@@ -3,16 +3,11 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class Role(Base):
|
||||
__tablename__ = "roles"
|
||||
|
||||
__tablename__ = 'roles'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
name = Column(String(50), unique=True, nullable=False, index=True)
|
||||
description = Column(String(255), nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
users = relationship("User", back_populates="role")
|
||||
|
||||
users = relationship('User', back_populates='role')
|
||||
@@ -4,36 +4,30 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class RoomStatus(str, enum.Enum):
|
||||
available = "available"
|
||||
occupied = "occupied"
|
||||
maintenance = "maintenance"
|
||||
cleaning = "cleaning"
|
||||
|
||||
available = 'available'
|
||||
occupied = 'occupied'
|
||||
maintenance = 'maintenance'
|
||||
cleaning = 'cleaning'
|
||||
|
||||
class Room(Base):
|
||||
__tablename__ = "rooms"
|
||||
|
||||
__tablename__ = 'rooms'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
room_type_id = Column(Integer, ForeignKey("room_types.id"), nullable=False)
|
||||
room_type_id = Column(Integer, ForeignKey('room_types.id'), nullable=False)
|
||||
room_number = Column(String(20), unique=True, nullable=False, index=True)
|
||||
floor = Column(Integer, nullable=False)
|
||||
status = Column(Enum(RoomStatus), nullable=False, default=RoomStatus.available)
|
||||
price = Column(Numeric(10, 2), nullable=False)
|
||||
featured = Column(Boolean, nullable=False, default=False)
|
||||
capacity = Column(Integer, nullable=True) # Room-specific capacity, overrides room_type capacity
|
||||
room_size = Column(String(50), nullable=True) # e.g., "1 Room", "2 Rooms", "50 sqm"
|
||||
view = Column(String(100), nullable=True) # e.g., "City View", "Ocean View", etc.
|
||||
capacity = Column(Integer, nullable=True)
|
||||
room_size = Column(String(50), nullable=True)
|
||||
view = Column(String(100), nullable=True)
|
||||
images = Column(JSON, nullable=True)
|
||||
amenities = Column(JSON, nullable=True)
|
||||
description = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
room_type = relationship("RoomType", back_populates="rooms")
|
||||
bookings = relationship("Booking", back_populates="room")
|
||||
reviews = relationship("Review", back_populates="room")
|
||||
favorites = relationship("Favorite", back_populates="room", cascade="all, delete-orphan")
|
||||
|
||||
room_type = relationship('RoomType', back_populates='rooms')
|
||||
bookings = relationship('Booking', back_populates='room')
|
||||
reviews = relationship('Review', back_populates='room')
|
||||
favorites = relationship('Favorite', back_populates='room', cascade='all, delete-orphan')
|
||||
@@ -3,10 +3,8 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class RoomType(Base):
|
||||
__tablename__ = "room_types"
|
||||
|
||||
__tablename__ = 'room_types'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
name = Column(String(100), unique=True, nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
@@ -15,7 +13,4 @@ class RoomType(Base):
|
||||
amenities = Column(JSON, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
rooms = relationship("Room", back_populates="room_type")
|
||||
|
||||
rooms = relationship('Room', back_populates='room_type')
|
||||
@@ -3,10 +3,8 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class Service(Base):
|
||||
__tablename__ = "services"
|
||||
|
||||
__tablename__ = 'services'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
name = Column(String(100), nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
@@ -15,7 +13,4 @@ class Service(Base):
|
||||
is_active = Column(Boolean, nullable=False, default=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
service_usages = relationship("ServiceUsage", back_populates="service")
|
||||
|
||||
service_usages = relationship('ServiceUsage', back_populates='service')
|
||||
@@ -4,66 +4,53 @@ from datetime import datetime
|
||||
import enum
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class ServiceBookingStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
confirmed = "confirmed"
|
||||
completed = "completed"
|
||||
cancelled = "cancelled"
|
||||
|
||||
pending = 'pending'
|
||||
confirmed = 'confirmed'
|
||||
completed = 'completed'
|
||||
cancelled = 'cancelled'
|
||||
|
||||
class ServiceBooking(Base):
|
||||
__tablename__ = "service_bookings"
|
||||
|
||||
__tablename__ = 'service_bookings'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
booking_number = Column(String(50), unique=True, nullable=False, index=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
|
||||
total_amount = Column(Numeric(10, 2), nullable=False)
|
||||
status = Column(Enum(ServiceBookingStatus), nullable=False, default=ServiceBookingStatus.pending)
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
user = relationship("User", back_populates="service_bookings")
|
||||
service_items = relationship("ServiceBookingItem", back_populates="service_booking", cascade="all, delete-orphan")
|
||||
payments = relationship("ServicePayment", back_populates="service_booking", cascade="all, delete-orphan")
|
||||
|
||||
user = relationship('User', back_populates='service_bookings')
|
||||
service_items = relationship('ServiceBookingItem', back_populates='service_booking', cascade='all, delete-orphan')
|
||||
payments = relationship('ServicePayment', back_populates='service_booking', cascade='all, delete-orphan')
|
||||
|
||||
class ServiceBookingItem(Base):
|
||||
__tablename__ = "service_booking_items"
|
||||
|
||||
__tablename__ = 'service_booking_items'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
service_booking_id = Column(Integer, ForeignKey("service_bookings.id"), nullable=False)
|
||||
service_id = Column(Integer, ForeignKey("services.id"), nullable=False)
|
||||
service_booking_id = Column(Integer, ForeignKey('service_bookings.id'), nullable=False)
|
||||
service_id = Column(Integer, ForeignKey('services.id'), nullable=False)
|
||||
quantity = Column(Integer, nullable=False, default=1)
|
||||
unit_price = Column(Numeric(10, 2), nullable=False)
|
||||
total_price = Column(Numeric(10, 2), nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
service_booking = relationship("ServiceBooking", back_populates="service_items")
|
||||
service = relationship("Service")
|
||||
|
||||
service_booking = relationship('ServiceBooking', back_populates='service_items')
|
||||
service = relationship('Service')
|
||||
|
||||
class ServicePaymentStatus(str, enum.Enum):
|
||||
pending = "pending"
|
||||
completed = "completed"
|
||||
failed = "failed"
|
||||
refunded = "refunded"
|
||||
|
||||
pending = 'pending'
|
||||
completed = 'completed'
|
||||
failed = 'failed'
|
||||
refunded = 'refunded'
|
||||
|
||||
class ServicePaymentMethod(str, enum.Enum):
|
||||
cash = "cash"
|
||||
stripe = "stripe"
|
||||
bank_transfer = "bank_transfer"
|
||||
|
||||
cash = 'cash'
|
||||
stripe = 'stripe'
|
||||
bank_transfer = 'bank_transfer'
|
||||
|
||||
class ServicePayment(Base):
|
||||
__tablename__ = "service_payments"
|
||||
|
||||
__tablename__ = 'service_payments'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
service_booking_id = Column(Integer, ForeignKey("service_bookings.id"), nullable=False)
|
||||
service_booking_id = Column(Integer, ForeignKey('service_bookings.id'), nullable=False)
|
||||
amount = Column(Numeric(10, 2), nullable=False)
|
||||
payment_method = Column(Enum(ServicePaymentMethod), nullable=False)
|
||||
payment_status = Column(Enum(ServicePaymentStatus), nullable=False, default=ServicePaymentStatus.pending)
|
||||
@@ -72,7 +59,4 @@ class ServicePayment(Base):
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
service_booking = relationship("ServiceBooking", back_populates="payments")
|
||||
|
||||
service_booking = relationship('ServiceBooking', back_populates='payments')
|
||||
@@ -3,13 +3,11 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class ServiceUsage(Base):
|
||||
__tablename__ = "service_usages"
|
||||
|
||||
__tablename__ = 'service_usages'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
booking_id = Column(Integer, ForeignKey("bookings.id"), nullable=False)
|
||||
service_id = Column(Integer, ForeignKey("services.id"), nullable=False)
|
||||
booking_id = Column(Integer, ForeignKey('bookings.id'), nullable=False)
|
||||
service_id = Column(Integer, ForeignKey('services.id'), nullable=False)
|
||||
quantity = Column(Integer, nullable=False, default=1)
|
||||
unit_price = Column(Numeric(10, 2), nullable=False)
|
||||
total_price = Column(Numeric(10, 2), nullable=False)
|
||||
@@ -17,8 +15,5 @@ class ServiceUsage(Base):
|
||||
notes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
booking = relationship("Booking", back_populates="service_usages")
|
||||
service = relationship("Service", back_populates="service_usages")
|
||||
|
||||
booking = relationship('Booking', back_populates='service_usages')
|
||||
service = relationship('Service', back_populates='service_usages')
|
||||
@@ -3,19 +3,12 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class SystemSettings(Base):
|
||||
"""
|
||||
System-wide settings controlled by administrators.
|
||||
Stores key-value pairs for platform configuration like currency, etc.
|
||||
"""
|
||||
__tablename__ = "system_settings"
|
||||
|
||||
__tablename__ = 'system_settings'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
key = Column(String(100), unique=True, nullable=False, index=True)
|
||||
value = Column(Text, nullable=False)
|
||||
description = Column(Text, nullable=True)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
updated_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
updated_by = relationship("User", lazy="joined")
|
||||
|
||||
updated_by_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||
updated_by = relationship('User', lazy='joined')
|
||||
@@ -3,33 +3,30 @@ from sqlalchemy.orm import relationship
|
||||
from datetime import datetime
|
||||
from ..config.database import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
__tablename__ = 'users'
|
||||
id = Column(Integer, primary_key=True, index=True, autoincrement=True)
|
||||
role_id = Column(Integer, ForeignKey("roles.id"), nullable=False)
|
||||
role_id = Column(Integer, ForeignKey('roles.id'), nullable=False)
|
||||
email = Column(String(100), unique=True, nullable=False, index=True)
|
||||
password = Column(String(255), nullable=False)
|
||||
full_name = Column(String(100), nullable=False)
|
||||
phone = Column(String(20), nullable=True)
|
||||
address = Column(Text, nullable=True)
|
||||
avatar = Column(String(255), nullable=True)
|
||||
currency = Column(String(3), nullable=False, default='VND') # ISO 4217 currency code
|
||||
currency = Column(String(3), nullable=False, default='VND')
|
||||
is_active = Column(Boolean, nullable=False, default=True)
|
||||
mfa_enabled = Column(Boolean, nullable=False, default=False)
|
||||
mfa_secret = Column(String(255), nullable=True) # TOTP secret key (encrypted in production)
|
||||
mfa_backup_codes = Column(Text, nullable=True) # JSON array of backup codes (hashed)
|
||||
mfa_secret = Column(String(255), nullable=True)
|
||||
mfa_backup_codes = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
# Relationships
|
||||
role = relationship("Role", back_populates="users")
|
||||
bookings = relationship("Booking", back_populates="user")
|
||||
refresh_tokens = relationship("RefreshToken", back_populates="user", cascade="all, delete-orphan")
|
||||
checkins_processed = relationship("CheckInCheckOut", foreign_keys="CheckInCheckOut.checkin_by", back_populates="checked_in_by")
|
||||
checkouts_processed = relationship("CheckInCheckOut", foreign_keys="CheckInCheckOut.checkout_by", back_populates="checked_out_by")
|
||||
reviews = relationship("Review", back_populates="user")
|
||||
favorites = relationship("Favorite", back_populates="user", cascade="all, delete-orphan")
|
||||
service_bookings = relationship("ServiceBooking", back_populates="user")
|
||||
|
||||
role = relationship('Role', back_populates='users')
|
||||
bookings = relationship('Booking', back_populates='user')
|
||||
refresh_tokens = relationship('RefreshToken', back_populates='user', cascade='all, delete-orphan')
|
||||
checkins_processed = relationship('CheckInCheckOut', foreign_keys='CheckInCheckOut.checkin_by', back_populates='checked_in_by')
|
||||
checkouts_processed = relationship('CheckInCheckOut', foreign_keys='CheckInCheckOut.checkout_by', back_populates='checked_out_by')
|
||||
reviews = relationship('Review', back_populates='user')
|
||||
favorites = relationship('Favorite', back_populates='user', cascade='all, delete-orphan')
|
||||
service_bookings = relationship('ServiceBooking', back_populates='user')
|
||||
visitor_chats = relationship('Chat', foreign_keys='Chat.visitor_id', back_populates='visitor')
|
||||
staff_chats = relationship('Chat', foreign_keys='Chat.staff_id', back_populates='staff')
|
||||
Reference in New Issue
Block a user