Files
AiTool/backend/app/models.py
2026-03-18 17:01:10 +08:00

111 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import date, datetime
from sqlalchemy import (
Date,
DateTime,
ForeignKey,
Integer,
Numeric,
String,
Text,
)
from sqlalchemy.orm import relationship, Mapped, mapped_column
from .db import Base
class Customer(Base):
__tablename__ = "customers"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
contact_info: Mapped[str | None] = mapped_column(String(512), nullable=True)
tags: Mapped[str | None] = mapped_column(String(512), nullable=True) # 逗号分隔,如:重点客户,已签约
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)
projects: Mapped[list["Project"]] = relationship(
"Project", back_populates="customer", cascade="all, delete-orphan"
)
class Project(Base):
"""
Project Archive: stores original requirement text and AI-generated solution.
"""
__tablename__ = "projects"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
customer_id: Mapped[int] = mapped_column(
Integer, ForeignKey("customers.id", ondelete="CASCADE"), nullable=False, index=True
)
raw_requirement: Mapped[str] = mapped_column(Text, nullable=False)
ai_solution_md: Mapped[str | None] = mapped_column(Text, nullable=True)
status: Mapped[str] = mapped_column(String(50), default="draft", nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)
customer: Mapped[Customer] = relationship("Customer", back_populates="projects")
quotes: Mapped[list["Quote"]] = relationship(
"Quote", back_populates="project", cascade="all, delete-orphan"
)
cloud_docs: Mapped[list["ProjectCloudDoc"]] = relationship(
"ProjectCloudDoc", back_populates="project", cascade="all, delete-orphan"
)
class ProjectCloudDoc(Base):
"""项目与云文档的映射,用于增量更新(有则 PATCH无则 POST"""
__tablename__ = "project_cloud_docs"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
project_id: Mapped[int] = mapped_column(
Integer, ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
)
platform: Mapped[str] = mapped_column(String(32), nullable=False, index=True) # feishu | yuque | tencent
cloud_doc_id: Mapped[str] = mapped_column(String(256), nullable=False)
cloud_url: Mapped[str | None] = mapped_column(String(512), nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False
)
project: Mapped["Project"] = relationship("Project", back_populates="cloud_docs")
class Quote(Base):
__tablename__ = "quotes"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
project_id: Mapped[int] = mapped_column(
Integer, ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
)
total_amount: Mapped[Numeric] = mapped_column(Numeric(12, 2), nullable=False)
file_path: Mapped[str] = mapped_column(String(512), nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)
project: Mapped[Project] = relationship("Project", back_populates="quotes")
class FinanceRecord(Base):
__tablename__ = "finance_records"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
month: Mapped[str] = mapped_column(String(7), nullable=False, index=True) # YYYY-MM
type: Mapped[str] = mapped_column(String(50), nullable=False) # invoice / bank_receipt / manual / ...
file_name: Mapped[str] = mapped_column(String(255), nullable=False)
file_path: Mapped[str] = mapped_column(String(512), nullable=False)
tags: Mapped[str | None] = mapped_column(String(512), nullable=True) # 逗号分隔标签
meta_json: Mapped[str | None] = mapped_column(Text, nullable=True) # 结构化识别结果 JSON
amount: Mapped[float | None] = mapped_column(Numeric(12, 2), nullable=True)
billing_date: Mapped[date | None] = mapped_column(Date, nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)