Files
server-core/alembic/versions/0056_task_system_v2.py
T

139 lines
8.3 KiB
Python

"""任务系统 v2:发布字段扩展 + 交付/里程碑/验收/发票表 + 标书扩展 + 评价唯一约束
Revision ID: 0056
Revises: 0055
"""
from alembic import op
import sqlalchemy as sa
revision = "0056"
down_revision = "0055"
branch_labels = None
depends_on = None
def upgrade() -> None:
# ── tasks 扩展字段(0056)──
op.add_column("tasks", sa.Column("resource_support_json", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("raw_materials_json", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("deliver_way", sa.String(length=20), nullable=False, server_default="online"))
op.add_column("tasks", sa.Column("deliver_items", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("accept_standard", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("price_type", sa.String(length=20), nullable=False, server_default="fixed"))
op.add_column("tasks", sa.Column("pay_type", sa.String(length=20), nullable=False, server_default="escrow"))
op.add_column("tasks", sa.Column("escrow_ratio", sa.Integer(), nullable=False, server_default="100"))
op.add_column("tasks", sa.Column("invoice_req", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("milestone_json", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("attachments_json", sa.Text(), nullable=False))
op.add_column("tasks", sa.Column("deliver_at", sa.String(length=40), nullable=False, server_default=""))
op.add_column("tasks", sa.Column("accepted_at", sa.String(length=40), nullable=False, server_default=""))
op.add_column("tasks", sa.Column("reject_count", sa.Integer(), nullable=False, server_default="0"))
op.add_column("tasks", sa.Column("settle_status", sa.String(length=20), nullable=False, server_default=""))
op.add_column("tasks", sa.Column("settled_at", sa.String(length=40), nullable=False, server_default=""))
op.add_column("tasks", sa.Column("on_time", sa.Boolean(), nullable=True))
op.add_column("tasks", sa.Column("contract_status", sa.String(length=20), nullable=False, server_default=""))
# ── bids 标书扩展 ──
op.add_column("bids", sa.Column("deliver_days", sa.Integer(), nullable=False, server_default="0"))
op.add_column("bids", sa.Column("team_json", sa.Text(), nullable=False))
op.add_column("bids", sa.Column("cases_json", sa.Text(), nullable=False))
op.add_column("bids", sa.Column("commit_json", sa.Text(), nullable=False))
op.add_column("bids", sa.Column("score_total", sa.Float(), nullable=False, server_default="0"))
op.add_column("bids", sa.Column("score_json", sa.Text(), nullable=False))
op.add_column("bids", sa.Column("review_note", sa.String(length=500), nullable=False, server_default=""))
# ── ratings:字段 + 唯一约束(先清理历史重复,保留最早一条)──
op.add_column("ratings", sa.Column("rating_type", sa.String(length=20), nullable=False, server_default="fulfill"))
op.add_column("ratings", sa.Column("dims_json", sa.Text(), nullable=False))
op.add_column("ratings", sa.Column("tags_json", sa.Text(), nullable=False))
op.execute(
"DELETE r1 FROM ratings r1 "
"INNER JOIN ratings r2 "
"ON r1.task_id = r2.task_id AND r1.from_id = r2.from_id AND r1.id > r2.id"
)
op.create_unique_constraint("uq_rating_task_from", "ratings", ["task_id", "from_id"])
# ── 新表:task_deliveries / task_milestones / task_acceptances / invoices ──
op.create_table(
"task_deliveries",
sa.Column("id", sa.String(length=64), primary_key=True),
sa.Column("task_id", sa.String(length=64), nullable=False, index=True),
sa.Column("milestone_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("version", sa.Integer(), nullable=False, server_default="1"),
sa.Column("attachments_json", sa.Text(), nullable=False),
sa.Column("note", sa.String(length=1000), nullable=False, server_default=""),
sa.Column("created_at", sa.String(length=40), nullable=False, server_default=""),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"], ondelete="CASCADE"),
)
op.create_table(
"task_milestones",
sa.Column("id", sa.String(length=64), primary_key=True),
sa.Column("task_id", sa.String(length=64), nullable=False, index=True),
sa.Column("index", sa.Integer(), nullable=False, server_default="1"),
sa.Column("name", sa.String(length=200), nullable=False, server_default=""),
sa.Column("desc", sa.String(length=1000), nullable=False, server_default=""),
sa.Column("days", sa.Integer(), nullable=False, server_default="0"),
sa.Column("deliverables_json", sa.Text(), nullable=False),
sa.Column("payment_ratio", sa.Float(), nullable=False, server_default="0"),
sa.Column("status", sa.String(length=20), nullable=False, server_default="pending"),
sa.Column("delivered_at", sa.String(length=40), nullable=False, server_default=""),
sa.Column("accepted_at", sa.String(length=40), nullable=False, server_default=""),
sa.Column("created_at", sa.String(length=40), nullable=False, server_default=""),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"], ondelete="CASCADE"),
)
op.create_table(
"task_acceptances",
sa.Column("id", sa.String(length=64), primary_key=True),
sa.Column("task_id", sa.String(length=64), nullable=False, index=True),
sa.Column("delivery_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("milestone_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("checklist_json", sa.Text(), nullable=False),
sa.Column("score_json", sa.Text(), nullable=False),
sa.Column("result", sa.String(length=20), nullable=False, server_default="pass"),
sa.Column("comment", sa.String(length=1000), nullable=False, server_default=""),
sa.Column("reviewer_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("created_at", sa.String(length=40), nullable=False, server_default=""),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"], ondelete="CASCADE"),
)
op.create_table(
"invoices",
sa.Column("id", sa.String(length=64), primary_key=True),
sa.Column("task_id", sa.String(length=64), nullable=False, index=True),
sa.Column("escrow_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("issuer_id", sa.String(length=64), nullable=False, server_default=""),
sa.Column("issuer_name", sa.String(length=200), nullable=False, server_default=""),
sa.Column("payer_name", sa.String(length=200), nullable=False, server_default=""),
sa.Column("amount", sa.Integer(), nullable=False, server_default="0"),
sa.Column("tax_rate", sa.Float(), nullable=False, server_default="0.01"),
sa.Column("invoice_type", sa.String(length=20), nullable=False, server_default="personal"),
sa.Column("status", sa.String(length=20), nullable=False, server_default="applied"),
sa.Column("invoice_no", sa.String(length=64), nullable=False, server_default=""),
sa.Column("created_at", sa.String(length=40), nullable=False, server_default=""),
sa.Column("issued_at", sa.String(length=40), nullable=False, server_default=""),
)
def downgrade() -> None:
op.drop_table("invoices")
op.drop_table("task_acceptances")
op.drop_table("task_milestones")
op.drop_table("task_deliveries")
op.drop_constraint("uq_rating_task_from", "ratings", type_="unique")
op.drop_column("ratings", "tags_json")
op.drop_column("ratings", "dims_json")
op.drop_column("ratings", "rating_type")
op.drop_column("bids", "review_note")
op.drop_column("bids", "score_json")
op.drop_column("bids", "score_total")
op.drop_column("bids", "commit_json")
op.drop_column("bids", "cases_json")
op.drop_column("bids", "team_json")
op.drop_column("bids", "deliver_days")
for col in (
"contract_status", "on_time", "settled_at", "settle_status", "reject_count",
"accepted_at", "deliver_at", "attachments_json", "milestone_json",
"invoice_req", "escrow_ratio", "pay_type", "price_type", "accept_standard",
"deliver_items", "deliver_way", "raw_materials_json", "resource_support_json",
):
op.drop_column("tasks", col)