137 lines
5.7 KiB
Python
137 lines
5.7 KiB
Python
"""
|
|
Event Calendar Models
|
|
Database models for tracking local events, promotions, and special occasions
|
|
"""
|
|
|
|
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, Float, Date
|
|
from sqlalchemy.dialects.postgresql import UUID
|
|
from shared.database.base import Base
|
|
from datetime import datetime, timezone
|
|
import uuid
|
|
|
|
|
|
class Event(Base):
|
|
"""
|
|
Table to track events that affect bakery demand.
|
|
|
|
Events include:
|
|
- Local events (festivals, markets, concerts)
|
|
- Promotions and sales
|
|
- Weather events (heat waves, storms)
|
|
- School holidays and breaks
|
|
- Special occasions
|
|
"""
|
|
__tablename__ = "events"
|
|
|
|
# Primary identification
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
|
|
|
# Event information
|
|
event_name = Column(String(500), nullable=False)
|
|
event_type = Column(String(100), nullable=False, index=True) # promotion, festival, holiday, weather, school_break, sport_event, etc.
|
|
description = Column(Text, nullable=True)
|
|
|
|
# Date and time
|
|
event_date = Column(Date, nullable=False, index=True)
|
|
start_time = Column(DateTime(timezone=True), nullable=True)
|
|
end_time = Column(DateTime(timezone=True), nullable=True)
|
|
is_all_day = Column(Boolean, default=True)
|
|
|
|
# Impact estimation
|
|
expected_impact = Column(String(50), nullable=True) # low, medium, high, very_high
|
|
impact_multiplier = Column(Float, nullable=True) # Expected demand multiplier (e.g., 1.5 = 50% increase)
|
|
affected_product_categories = Column(String(500), nullable=True) # Comma-separated categories
|
|
|
|
# Location
|
|
location = Column(String(500), nullable=True)
|
|
is_local = Column(Boolean, default=True) # True if event is near bakery
|
|
|
|
# Status
|
|
is_confirmed = Column(Boolean, default=False)
|
|
is_recurring = Column(Boolean, default=False)
|
|
recurrence_pattern = Column(String(200), nullable=True) # e.g., "weekly:monday", "monthly:first_saturday"
|
|
|
|
# Actual impact (filled after event)
|
|
actual_impact_multiplier = Column(Float, nullable=True)
|
|
actual_sales_increase_percent = Column(Float, nullable=True)
|
|
|
|
# Metadata
|
|
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
created_by = Column(String(255), nullable=True)
|
|
notes = Column(Text, nullable=True)
|
|
|
|
def to_dict(self):
|
|
return {
|
|
"id": str(self.id),
|
|
"tenant_id": str(self.tenant_id),
|
|
"event_name": self.event_name,
|
|
"event_type": self.event_type,
|
|
"description": self.description,
|
|
"event_date": self.event_date.isoformat() if self.event_date else None,
|
|
"start_time": self.start_time.isoformat() if self.start_time else None,
|
|
"end_time": self.end_time.isoformat() if self.end_time else None,
|
|
"is_all_day": self.is_all_day,
|
|
"expected_impact": self.expected_impact,
|
|
"impact_multiplier": self.impact_multiplier,
|
|
"affected_product_categories": self.affected_product_categories,
|
|
"location": self.location,
|
|
"is_local": self.is_local,
|
|
"is_confirmed": self.is_confirmed,
|
|
"is_recurring": self.is_recurring,
|
|
"recurrence_pattern": self.recurrence_pattern,
|
|
"actual_impact_multiplier": self.actual_impact_multiplier,
|
|
"actual_sales_increase_percent": self.actual_sales_increase_percent,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
"created_by": self.created_by,
|
|
"notes": self.notes
|
|
}
|
|
|
|
|
|
class EventTemplate(Base):
|
|
"""
|
|
Template for recurring events.
|
|
Allows easy creation of events based on patterns.
|
|
"""
|
|
__tablename__ = "event_templates"
|
|
|
|
# Primary identification
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
|
|
|
# Template information
|
|
template_name = Column(String(500), nullable=False)
|
|
event_type = Column(String(100), nullable=False)
|
|
description = Column(Text, nullable=True)
|
|
|
|
# Default values
|
|
default_impact = Column(String(50), nullable=True)
|
|
default_impact_multiplier = Column(Float, nullable=True)
|
|
default_affected_categories = Column(String(500), nullable=True)
|
|
|
|
# Recurrence
|
|
recurrence_pattern = Column(String(200), nullable=False) # e.g., "weekly:saturday", "monthly:last_sunday"
|
|
is_active = Column(Boolean, default=True)
|
|
|
|
# Metadata
|
|
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
|
|
|
|
def to_dict(self):
|
|
return {
|
|
"id": str(self.id),
|
|
"tenant_id": str(self.tenant_id),
|
|
"template_name": self.template_name,
|
|
"event_type": self.event_type,
|
|
"description": self.description,
|
|
"default_impact": self.default_impact,
|
|
"default_impact_multiplier": self.default_impact_multiplier,
|
|
"default_affected_categories": self.default_affected_categories,
|
|
"recurrence_pattern": self.recurrence_pattern,
|
|
"is_active": self.is_active,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None
|
|
}
|