feat: 添加生命周期报告和AI规则管理功能 - 在Dockerfile中添加pillow依赖包用于图像处理 - 实现生命周期报告调度任务,支持日报和周报两种类型 - 新增TASK_RUN_LIFECYCLE任务常量和相关配置选项 - 扩展AI Agent服务以支持用户规则,并在分析时应用规则 - 添加AI用户规则创建、更新和查询接口 - 增加项目生命周期和财务需求分析技能 - 扩展现有模型以支持更完整的业务数据字段 - 实现飞书图片上传功能用于报告展示 ```
119 lines
4.8 KiB
Python
119 lines
4.8 KiB
Python
"""Add project contracts and normalized cash flows.
|
|
|
|
Revision ID: 202607120002
|
|
Revises: 202607120001
|
|
Create Date: 2026-07-12
|
|
"""
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
revision = "202607120002"
|
|
down_revision = "202607120001"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def _index(table: str, column: str, unique: bool = False) -> None:
|
|
op.create_index(op.f(f"ix_{table}_{column}"), table, [column], unique=unique)
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"projects", sa.Column("source_contract_amount", sa.Numeric(16, 2), nullable=True)
|
|
)
|
|
op.add_column(
|
|
"projects",
|
|
sa.Column("source_project_investment_amount", sa.Numeric(16, 2), nullable=True),
|
|
)
|
|
|
|
op.create_table(
|
|
"project_contracts",
|
|
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
|
sa.Column("code", sa.String(64), nullable=False),
|
|
sa.Column("project_code", sa.String(64), nullable=True),
|
|
sa.Column("contract_type_code", sa.String(32), nullable=True),
|
|
sa.Column("contract_type_label", sa.String(128), nullable=True),
|
|
sa.Column("amount", sa.Numeric(16, 2), nullable=False),
|
|
sa.Column("signed_date", sa.Date(), nullable=True),
|
|
sa.Column("start_date", sa.Date(), nullable=True),
|
|
sa.Column("end_date", sa.Date(), nullable=True),
|
|
sa.Column("invoice_type_code", sa.String(32), nullable=True),
|
|
sa.Column("data_quality_status", sa.String(32), nullable=False),
|
|
sa.Column("source_system", sa.String(64), nullable=False),
|
|
sa.Column("external_id", sa.String(128), nullable=False),
|
|
sa.Column("source_created_at", sa.DateTime(), nullable=True),
|
|
sa.Column("last_seen_at", sa.DateTime(), nullable=True),
|
|
sa.Column("is_active", sa.Boolean(), nullable=False),
|
|
sa.Column("created_at", sa.DateTime(), nullable=False),
|
|
sa.Column("updated_at", sa.DateTime(), nullable=False),
|
|
sa.PrimaryKeyConstraint("id"),
|
|
)
|
|
for column, unique in (
|
|
("code", True),
|
|
("project_code", False),
|
|
("contract_type_code", False),
|
|
("signed_date", False),
|
|
("data_quality_status", False),
|
|
("external_id", False),
|
|
("last_seen_at", False),
|
|
("is_active", False),
|
|
):
|
|
_index("project_contracts", column, unique)
|
|
|
|
op.create_table(
|
|
"project_cash_flows",
|
|
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
|
|
sa.Column("code", sa.String(64), nullable=False),
|
|
sa.Column("project_code", sa.String(64), nullable=True),
|
|
sa.Column("contract_code", sa.String(64), nullable=True),
|
|
sa.Column("flow_type", sa.String(32), nullable=False),
|
|
sa.Column("direction", sa.String(16), nullable=False),
|
|
sa.Column("category_code", sa.String(32), nullable=True),
|
|
sa.Column("category_label", sa.String(128), nullable=True),
|
|
sa.Column("planned_amount", sa.Numeric(16, 2), nullable=False),
|
|
sa.Column("actual_amount", sa.Numeric(16, 2), nullable=True),
|
|
sa.Column("planned_date", sa.Date(), nullable=True),
|
|
sa.Column("actual_date", sa.Date(), nullable=True),
|
|
sa.Column("payment_status", sa.String(32), nullable=True),
|
|
sa.Column("invoice_status", sa.String(32), nullable=True),
|
|
sa.Column("approval_status", sa.String(32), nullable=True),
|
|
sa.Column("confirmation_status", sa.String(32), nullable=True),
|
|
sa.Column("data_quality_status", sa.String(32), nullable=False),
|
|
sa.Column("source_system", sa.String(64), nullable=False),
|
|
sa.Column("external_id", sa.String(128), nullable=False),
|
|
sa.Column("source_created_at", sa.DateTime(), nullable=True),
|
|
sa.Column("source_updated_at", sa.DateTime(), nullable=True),
|
|
sa.Column("last_seen_at", sa.DateTime(), nullable=True),
|
|
sa.Column("is_active", sa.Boolean(), nullable=False),
|
|
sa.Column("created_at", sa.DateTime(), nullable=False),
|
|
sa.Column("updated_at", sa.DateTime(), nullable=False),
|
|
sa.PrimaryKeyConstraint("id"),
|
|
)
|
|
for column, unique in (
|
|
("code", True),
|
|
("project_code", False),
|
|
("contract_code", False),
|
|
("flow_type", False),
|
|
("direction", False),
|
|
("category_code", False),
|
|
("planned_date", False),
|
|
("actual_date", False),
|
|
("payment_status", False),
|
|
("approval_status", False),
|
|
("data_quality_status", False),
|
|
("external_id", False),
|
|
("source_updated_at", False),
|
|
("last_seen_at", False),
|
|
("is_active", False),
|
|
):
|
|
_index("project_cash_flows", column, unique)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_table("project_cash_flows")
|
|
op.drop_table("project_contracts")
|
|
op.drop_column("projects", "source_project_investment_amount")
|
|
op.drop_column("projects", "source_contract_amount")
|