351 lines
14 KiB
Python
351 lines
14 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import (
|
|
Column, Integer, String, Boolean, Text, DateTime, BigInteger, SmallInteger, JSON, ForeignKey, CheckConstraint, text as sa_text
|
|
)
|
|
from sqlalchemy.orm import relationship, declarative_base
|
|
|
|
Base = declarative_base()
|
|
|
|
|
|
class BotUser(Base):
|
|
__tablename__ = "bot_users"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
max_user_id = Column(BigInteger, unique=True, nullable=False)
|
|
first_name = Column(String(255), default="")
|
|
last_name = Column(String(255), default="")
|
|
username = Column(String(255), default="")
|
|
phone = Column(String(50), default="")
|
|
email = Column(String(255), default="")
|
|
consent_given = Column(Boolean, nullable=False, default=False)
|
|
consent_timestamp = Column(DateTime, nullable=True)
|
|
consent_method = Column(String(50), default="")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
last_active_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
conversations = relationship("BotConversation", back_populates="user")
|
|
consent_logs = relationship("BotConsentLog", back_populates="user")
|
|
notification_subscriptions = relationship("BotNotificationSubscription", back_populates="user", uselist=False)
|
|
|
|
|
|
class BotConversation(Base):
|
|
__tablename__ = "bot_conversations"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
user_id = Column(Integer, ForeignKey("bot_users.id", ondelete="CASCADE"), nullable=False)
|
|
status = Column(String(20), nullable=False, default="open")
|
|
inquiry_type = Column(Integer, ForeignKey("bot_categories.id", ondelete="SET NULL"), nullable=True)
|
|
inquiry_text = Column(Text, default="")
|
|
priority = Column(String(20), default="normal")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
closed_at = Column(DateTime, nullable=True)
|
|
assigned_to = Column(String(255), default="")
|
|
has_attachment = Column(Boolean, default=False)
|
|
attachment_type = Column(String(50), default="")
|
|
attachment_path = Column(String(500), default="")
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("status IN ('open','closed','handoff','1c_sent','awaiting_rating')", name="ck_bot_conv_status"),
|
|
CheckConstraint("priority IN ('low','normal','high','urgent')", name="ck_bot_conv_priority"),
|
|
)
|
|
|
|
user = relationship("BotUser", back_populates="conversations")
|
|
category = relationship("BotCategory", back_populates="conversations")
|
|
messages = relationship("BotMessage", back_populates="conversation", order_by="BotMessage.timestamp")
|
|
sync_log = relationship("Bot1CSyncLog", back_populates="conversation")
|
|
|
|
|
|
class BotMessage(Base):
|
|
__tablename__ = "bot_messages"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
conversation_id = Column(Integer, ForeignKey("bot_conversations.id", ondelete="CASCADE"), nullable=False)
|
|
direction = Column(String(3), nullable=False)
|
|
text = Column(Text, default="")
|
|
has_attachment = Column(Boolean, default=False)
|
|
attachment_type = Column(String(50), default="")
|
|
attachment_path = Column(String(500), default="")
|
|
max_message_id = Column(BigInteger, nullable=True)
|
|
timestamp = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("direction IN ('in','out')", name="ck_bot_msg_direction"),
|
|
)
|
|
|
|
conversation = relationship("BotConversation", back_populates="messages")
|
|
|
|
|
|
class BotConsentLog(Base):
|
|
__tablename__ = "bot_consent_logs"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
user_id = Column(Integer, ForeignKey("bot_users.id", ondelete="CASCADE"), nullable=False)
|
|
action = Column(String(20), nullable=False)
|
|
timestamp = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
method = Column(String(50), default="")
|
|
ip_address = Column(String(45), default="")
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("action IN ('given','revoked')", name="ck_bot_consent_action"),
|
|
)
|
|
|
|
user = relationship("BotUser", back_populates="consent_logs")
|
|
|
|
|
|
class Bot1CSyncLog(Base):
|
|
__tablename__ = "bot_1c_sync_log"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
conversation_id = Column(Integer, ForeignKey("bot_conversations.id", ondelete="CASCADE"), nullable=False)
|
|
status = Column(String(20), nullable=False, default="pending")
|
|
request_payload = Column(Text, default="")
|
|
response_payload = Column(Text, default="")
|
|
sent_at = Column(DateTime, nullable=True)
|
|
confirmed_at = Column(DateTime, nullable=True)
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("status IN ('pending','sent','confirmed','error')", name="ck_bot_1c_status"),
|
|
)
|
|
|
|
conversation = relationship("BotConversation", back_populates="sync_log")
|
|
|
|
|
|
class BotKnowledgeBase(Base):
|
|
__tablename__ = "bot_knowledge_base"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
question = Column(String(500), nullable=False)
|
|
answer = Column(Text, nullable=False)
|
|
category = Column(String(100), default="")
|
|
keywords = Column(JSON, default=list)
|
|
active = Column(Boolean, nullable=False, default=True)
|
|
sort_order = Column(Integer, default=0)
|
|
|
|
|
|
class BotCategory(Base):
|
|
__tablename__ = "bot_categories"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
name = Column(String(100), nullable=False)
|
|
description = Column(String(500), default="")
|
|
active = Column(Boolean, nullable=False, default=True)
|
|
sort_order = Column(Integer, default=0)
|
|
icon_emoji = Column(String(10), default="📋")
|
|
keywords = Column(JSON, default=list)
|
|
|
|
conversations = relationship("BotConversation", back_populates="category")
|
|
|
|
|
|
class BotSetting(Base):
|
|
__tablename__ = "bot_settings"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
key = Column(String(100), unique=True, nullable=False)
|
|
value = Column(Text, default="")
|
|
description = Column(String(500), default="")
|
|
|
|
|
|
class BotFeature(Base):
|
|
__tablename__ = "bot_features"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
feature_key = Column(String(100), unique=True, nullable=False)
|
|
name = Column(String(100), nullable=False)
|
|
description = Column(String(500), default="")
|
|
enabled = Column(Boolean, nullable=False, default=False)
|
|
sort_order = Column(Integer, default=0)
|
|
|
|
|
|
class BotResponseTemplate(Base):
|
|
__tablename__ = "bot_response_templates"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
template_key = Column(String(100), unique=True, nullable=False)
|
|
template_text = Column(Text, nullable=False)
|
|
description = Column(String(500), default="")
|
|
variables = Column(JSON, default=list)
|
|
|
|
|
|
class FileSyncQueue(Base):
|
|
__tablename__ = "file_sync_queue"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
local_path = Column(String(500), nullable=False)
|
|
remote_path = Column(String(500), default="")
|
|
entity_type = Column(String(50), nullable=False)
|
|
entity_id = Column(Integer, nullable=False)
|
|
status = Column(String(20), nullable=False, default="pending")
|
|
error = Column(Text, default="")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("status IN ('pending','uploading','synced','error')", name="ck_file_sync_status"),
|
|
)
|
|
|
|
|
|
class BotBroadcast(Base):
|
|
__tablename__ = "bot_broadcasts"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
text = Column(Text, nullable=False)
|
|
sent_at = Column(DateTime, nullable=True)
|
|
sent_by = Column(Integer, nullable=True)
|
|
recipient_count = Column(Integer, default=0)
|
|
recipient_ids = Column(JSON, default=list)
|
|
status = Column(String(20), default="draft")
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("status IN ('draft','sent','failed')", name="ck_bot_broadcast_status"),
|
|
)
|
|
|
|
|
|
class BotNotification(Base):
|
|
__tablename__ = "bot_notifications"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
type = Column(String(50), nullable=False)
|
|
recipient_type = Column(String(20), nullable=False)
|
|
recipient_max_user_id = Column(BigInteger, nullable=True)
|
|
title = Column(String(255), default="")
|
|
body = Column(Text, default="")
|
|
related_type = Column(String(50), default="")
|
|
related_id = Column(Integer, nullable=True)
|
|
is_read = Column(Boolean, nullable=False, default=False)
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("recipient_type IN ('operator','level2','client')", name="ck_bot_notif_recipient"),
|
|
)
|
|
|
|
|
|
class BotNotificationSubscription(Base):
|
|
__tablename__ = "bot_notification_subscriptions"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
user_id = Column(Integer, ForeignKey("bot_users.id", ondelete="CASCADE"), nullable=False)
|
|
notify_on_status_change = Column(Boolean, nullable=False, default=False)
|
|
notify_on_reply = Column(Boolean, nullable=False, default=False)
|
|
notify_on_broadcast = Column(Boolean, nullable=False, default=False)
|
|
|
|
user = relationship("BotUser", back_populates="notification_subscriptions")
|
|
|
|
|
|
class Customer(Base):
|
|
__tablename__ = "customers"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
name = Column(String(255), nullable=False)
|
|
contact_phone = Column(String(50), default="")
|
|
|
|
|
|
class Object(Base):
|
|
__tablename__ = "objects"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
customer_id = Column(Integer, ForeignKey("customers.id", ondelete="SET NULL"), nullable=True)
|
|
name = Column(String(255), nullable=False)
|
|
status = Column(String(20), nullable=False, default="active")
|
|
risk_score = Column(Integer, default=0)
|
|
|
|
|
|
class SLAContract(Base):
|
|
__tablename__ = "sla_contracts"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
object_id = Column(Integer, ForeignKey("objects.id", ondelete="CASCADE"), nullable=False)
|
|
status = Column(String(20), nullable=False, default="negotiation")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
service_level = Column(String(20), default="start")
|
|
sla_price_monthly = Column(Integer, default=0)
|
|
|
|
|
|
class Task(Base):
|
|
__tablename__ = "tasks"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
object_id = Column(Integer, ForeignKey("objects.id", ondelete="CASCADE"), nullable=False)
|
|
status = Column(String(20), nullable=False, default="open")
|
|
|
|
|
|
class Incident(Base):
|
|
__tablename__ = "incidents"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
object_id = Column(Integer, ForeignKey("objects.id", ondelete="CASCADE"), nullable=False)
|
|
status = Column(String(20), nullable=False, default="open")
|
|
created_at = Column(DateTime, nullable=False, server_default="NOW()")
|
|
title = Column(String(500), default="")
|
|
description = Column(Text, default="")
|
|
severity = Column(String(4), nullable=False, default="P3")
|
|
reported_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
login = Column(String(50), default="")
|
|
full_name = Column(String(255), default="")
|
|
role = Column(String(20), nullable=False, default="technician")
|
|
is_active = Column(Boolean, nullable=False, default=True)
|
|
max_user_id = Column(BigInteger, nullable=True)
|
|
|
|
|
|
class BotRiskQuestion(Base):
|
|
__tablename__ = "bot_risk_questions"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
question_key = Column(String(100), unique=True, nullable=False)
|
|
question = Column(String(500), nullable=False)
|
|
weight = Column(Integer, nullable=False, default=10)
|
|
sort_order = Column(Integer, default=0)
|
|
is_active = Column(Boolean, nullable=False, default=True)
|
|
|
|
|
|
class BotTicket(Base):
|
|
__tablename__ = "bot_tickets"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
ticket_number = Column(String(20), unique=True, nullable=False)
|
|
user_id = Column(Integer, ForeignKey("bot_users.id", ondelete="SET NULL"), nullable=True)
|
|
object_id = Column(Integer, nullable=True)
|
|
customer_id = Column(Integer, nullable=True)
|
|
title = Column(String(255), nullable=False)
|
|
description = Column(Text, default="")
|
|
priority = Column(String(20), default="normal")
|
|
status = Column(String(20), nullable=False, default="open")
|
|
created_by = Column(String(20), default="bot")
|
|
sla_contract_id = Column(Integer, nullable=True)
|
|
has_attachment = Column(Boolean, default=False)
|
|
attachment_type = Column(String(50), default="")
|
|
attachment_path = Column(String(500), default="")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
updated_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
__table_args__ = (
|
|
CheckConstraint("priority IN ('low','normal','high','urgent')", name="ck_bot_ticket_priority"),
|
|
CheckConstraint("status IN ('open','in_progress','resolved','closed')", name="ck_bot_ticket_status"),
|
|
)
|
|
|
|
|
|
class BotTicketMessage(Base):
|
|
__tablename__ = "bot_ticket_messages"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
ticket_id = Column(Integer, ForeignKey("bot_tickets.id", ondelete="CASCADE"), nullable=False)
|
|
direction = Column(String(10), nullable=False)
|
|
text = Column(Text, default="")
|
|
sender = Column(String(50), default="")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|
|
|
|
|
|
class BotTicketStatus(Base):
|
|
__tablename__ = "bot_ticket_statuses"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
ticket_id = Column(Integer, ForeignKey("bot_tickets.id", ondelete="CASCADE"), nullable=False)
|
|
old_status = Column(String(20), default="")
|
|
new_status = Column(String(20), nullable=False)
|
|
changed_by = Column(String(50), default="")
|
|
created_at = Column(DateTime, nullable=False, server_default=sa_text("CURRENT_TIMESTAMP"))
|