Files
bakery-ia/services/tenant/app/models/events.py
2025-11-05 13:34:56 +01:00

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
}