fix(seed): 客户种子改为已开户;portal.py 标注为调试工具

- seed_test_rbac.py 把 fund_account_status 硬编码成 'closed',与 create_test_user.py
  的 {customer: 已开户, employee: closed} 口径不一致,导致种子建的客户永远未开户
- 影响:GET /users/me/account/dashboard、/users/me/cash-ledger 恒返回 404,
  正式前端 T001/T009 两个页面打不开(端点本身是好的)
- 改为按 user_type 取状态;配合 tools/seed_sim_account_demo.py 开虚拟资金账户后
  T001/T006/T007/T009 全部 200
- tools/portal.py:正式前端已在 app/static/portal/,本工具降级为跨角色联调工具
This commit is contained in:
2026-09-13 16:19:54 +08:00
parent f7f43742fd
commit f4eaa2f631
+21 -4
View File
@@ -186,6 +186,16 @@ USERS: tuple[tuple[int, str, str, str], ...] = (
(9004, "T-REVIEW", "review_t", "employee"),
)
#: `sys_user.user_type` → `fund_account_status`。口径与 `tools/create_test_user.py`
#: 的 `FUND_ACCOUNT_STATUS` **必须一致**:客户只有"已开户"才能访问账户域接口,
#: 员工账号没有基金账户。此前这里(以及 INSERT 语句)硬编码写死 `'closed'`,
#: 于是种子建的客户永远"未开户"—— `GET /api/v1/users/me/account/dashboard` 与
#: `GET /api/v1/users/me/cash-ledger` 会返回 404「客户未开户」,前端对应页面直接打不开。
FUND_ACCOUNT_STATUS_BY_USER_TYPE: dict[str, str] = {
"customer": "已开户",
"employee": "closed",
}
#: 用户 → 角色绑定,**显式列出**而不是按位置配对。
#:
#: 原先写的是 `zip(user_ids, role_ids, strict=True)`,隐含假设「USERS 与 ROLES 一一对应」;
@@ -244,13 +254,20 @@ async def seed() -> None:
# 一起弄丢。改为下面循环里的「更新或插入」,且不覆盖 password_hash。
for user_id, user_no, user_name, user_type in USERS:
# 开户状态按角色区分,与 `tools/create_test_user.py` 的 FUND_ACCOUNT_STATUS 口径一致:
# **客户必须"已开户"**,否则账户域接口会一律 404「客户未开户」——
# 实测受影响的是 `GET /api/v1/users/me/account/dashboard`(前端 T001)与
# `GET /api/v1/users/me/cash-ledger`(T009),页面直接打不开。
# 员工账号没有基金账户,保持 closed。
fund_status = FUND_ACCOUNT_STATUS_BY_USER_TYPE.get(user_type, "closed")
updated = await session.execute(
text(
"UPDATE sys_user SET user_no=:no, username=:name, user_type=:type,"
" professional_investor_status='none', fund_account_status='closed',"
" professional_investor_status='none', fund_account_status=:fund,"
" status='正常', updated_at=:now WHERE id=:id"
),
{"id": user_id, "no": user_no, "name": user_name, "type": user_type, "now": now},
{"id": user_id, "no": user_no, "name": user_name, "type": user_type,
"fund": fund_status, "now": now},
)
if updated.rowcount == 0:
await session.execute(
@@ -258,10 +275,10 @@ async def seed() -> None:
"INSERT INTO sys_user (id, user_no, username, password_hash, user_type,"
" professional_investor_status, fund_account_status, status,"
" created_at, updated_at)"
" VALUES (:id,:no,:name,'x',:type,'none','closed','正常',:now,:now)"
" VALUES (:id,:no,:name,'x',:type,'none',:fund,'正常',:now,:now)"
),
{"id": user_id, "no": user_no, "name": user_name,
"type": user_type, "now": now},
"type": user_type, "fund": fund_status, "now": now},
)
for role_id, role_code, role_name in ROLES:
await session.execute(