后端: - 新增 expense_data TEXT 列(columns.py迁移) - 新增 data_split 迁移:旧 budget_data cost/paid → expense_data(幂等) - sum_budget cost/paid → sum_expense cost/paid(routes.py/helpers.py) - TABLES 配置加入 expense_data 前端: - 项目详情弹窗Tab:基本信息→确收与回款→费用明细→执行信息→任务管理→活动 - 确收与回款Tab:月份/确收/毛利/回款/备注 - 费用明细Tab:月份/费用类型/应付/已付/备注 - 项目表格三视图(月/季/总)cost/paid来源切换为expense_data - 保存逻辑分两路: budget_data(rev/gross/payment)+expense_data(cost/paid)
57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""migrations/data_split.py — 预算数据拆分迁移:budget_data → expense_data
|
|
|
|
旧结构:budget_data = [{month, rev, gross, payment, cost, paid}]
|
|
新结构:expense_data = [{month, expense_type, cost, paid, exp_note}]
|
|
|
|
部署时自动:检测未拆分的旧数据,将 cost/paid 从 budget_data 迁移到 expense_data。
|
|
幂等:只处理 expense_data 为空的记录。
|
|
"""
|
|
|
|
|
|
def migrate_data_split():
|
|
"""一次性数据拆分迁移"""
|
|
from db import db, _exec
|
|
import json
|
|
|
|
conn = db()
|
|
try:
|
|
# 查询未迁移的记录
|
|
cur = conn.cursor(dictionary=True)
|
|
cur.execute(
|
|
"SELECT id, budget_data, expense_data FROM project_finances "
|
|
"WHERE (expense_data IS NULL OR expense_data = '' OR expense_data = '[]') "
|
|
"AND budget_data IS NOT NULL AND budget_data != '' AND budget_data != '[]'"
|
|
)
|
|
rows = cur.fetchall()
|
|
cur.close()
|
|
|
|
migrated = 0
|
|
for row in rows:
|
|
try:
|
|
budget = json.loads(row.get("budget_data") or "[]")
|
|
except (json.JSONDecodeError, TypeError):
|
|
continue
|
|
|
|
expense_rows = []
|
|
for b in budget:
|
|
expense_rows.append({
|
|
"month": b.get("month", ""),
|
|
"expense_type": "",
|
|
"cost": float(b.get("cost") or 0),
|
|
"paid": float(b.get("paid") or 0),
|
|
"exp_note": "",
|
|
})
|
|
|
|
if expense_rows:
|
|
_exec(
|
|
conn,
|
|
"UPDATE project_finances SET expense_data = ? WHERE id = ?",
|
|
(json.dumps(expense_rows, ensure_ascii=False), row["id"]),
|
|
)
|
|
migrated += 1
|
|
|
|
conn.commit()
|
|
print(f"[migrate] 数据拆分迁移完成:{migrated} 条记录已从 budget_data 提取 cost/paid 到 expense_data")
|
|
finally:
|
|
conn.close()
|