feat(fund): 备用金账户编号改为带用户名的可读编号
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
-- 113_fund_account_no_readable.sql —— 备用金账户编号改为可读的 FA-<用户名>。
|
||||
--
|
||||
-- 背景:历史编号是 FA + 10 位随机十六进制(如 FA7683D6B58B),
|
||||
-- 在「备用金」列表里无法一眼对应到具体客服。
|
||||
-- 新规则:FA-<大写用户名>,例如 FA-KF_2、FA-JIAJIALI;
|
||||
-- 同一用户名重名时追加 -2、-3。
|
||||
|
||||
WITH base AS (
|
||||
SELECT
|
||||
fa.id,
|
||||
'FA-' || COALESCE(
|
||||
NULLIF(
|
||||
trim(
|
||||
both '_' FROM upper(
|
||||
regexp_replace(COALESCE(NULLIF(au.username, ''), 'account-' || fa.id), '[^A-Za-z0-9_]+', '_', 'g')
|
||||
)
|
||||
),
|
||||
''
|
||||
),
|
||||
'ACCOUNT-' || fa.id
|
||||
) AS base_no
|
||||
FROM fund_accounts fa
|
||||
LEFT JOIN admin_users au ON au.id = fa.owner_admin_user_id
|
||||
),
|
||||
numbered AS (
|
||||
SELECT
|
||||
id,
|
||||
base_no,
|
||||
row_number() OVER (PARTITION BY base_no ORDER BY id) AS rn
|
||||
FROM base
|
||||
)
|
||||
UPDATE fund_accounts fa
|
||||
SET account_no = CASE WHEN n.rn = 1 THEN n.base_no ELSE n.base_no || '-' || n.rn END
|
||||
FROM numbered n
|
||||
WHERE fa.id = n.id;
|
||||
@@ -278,6 +278,37 @@ function generateNo(prefix: string) {
|
||||
return randomId(prefix, 5).toUpperCase()
|
||||
}
|
||||
|
||||
function buildFundAccountNoBase(username: string): string {
|
||||
const slug =
|
||||
String(username || '')
|
||||
.trim()
|
||||
.replace(/[^A-Za-z0-9_]+/g, '_')
|
||||
.replace(/^_+|_+$/g, '')
|
||||
.toUpperCase()
|
||||
.slice(0, 32) || 'ACCOUNT'
|
||||
return `FA-${slug}`
|
||||
}
|
||||
|
||||
/** 账户编号直接带用户名,列表里一眼能对应到人;重名时追加 -2、-3。 */
|
||||
async function allocateFundAccountNo(client: PoolClient, username: string): Promise<string> {
|
||||
const base = buildFundAccountNoBase(username)
|
||||
let candidate = base
|
||||
for (let suffix = 2; suffix <= 99; suffix += 1) {
|
||||
const existing = await client.query(
|
||||
'SELECT 1 FROM fund_accounts WHERE account_no = $1 LIMIT 1',
|
||||
[candidate],
|
||||
)
|
||||
if (!existing.rowCount) {
|
||||
return candidate
|
||||
}
|
||||
candidate = `${base}-${suffix}`
|
||||
}
|
||||
throw createHttpError('生成备用金账户编号失败', {
|
||||
statusCode: 500,
|
||||
errorCode: 'fund_account_no_conflict',
|
||||
})
|
||||
}
|
||||
|
||||
function requiredRow<T>(row: T | undefined, message: string): T {
|
||||
if (!row) {
|
||||
throw createHttpError(message, {
|
||||
@@ -974,7 +1005,7 @@ export async function createAdminFundAccount(payload: JsonObject, session: Admin
|
||||
})
|
||||
}
|
||||
|
||||
const accountNo = generateNo('FA')
|
||||
const accountNo = await allocateFundAccountNo(client, user.username)
|
||||
const insertResult = await client.query<FundAccountRow>(
|
||||
`
|
||||
INSERT INTO fund_accounts (
|
||||
@@ -1062,7 +1093,7 @@ export async function ensureAdminFundAgentAccounts(payload: JsonObject, session:
|
||||
|
||||
const created: Array<{ id: number; accountNo: string; ownerName: string }> = []
|
||||
for (const user of usersResult.rows) {
|
||||
const accountNo = generateNo('FA')
|
||||
const accountNo = await allocateFundAccountNo(client, user.username)
|
||||
const insertResult = await client.query<FundAccountRow>(
|
||||
`
|
||||
INSERT INTO fund_accounts (
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# order_site 文档索引
|
||||
|
||||
> 最后校准:2026-10-22,代码基线 `dev @ 7c883207 + 财务 103–112`。
|
||||
> 最后校准:2026-10-23,代码基线 `dev @ a7f60414 + 财务 103–113`。
|
||||
> 本文是 `docs/` 的唯一入口。新增文档必须在上表登记状态;过期文档不再直接改写结论,统一移入 `docs/archive/`。
|
||||
|
||||
## 一、先记住五条口径
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> 状态:**已实施 P0(`dev` 分支,迁移 111;订单页人工录单、备用金扣款为 2026-10-22/23 增量)**
|
||||
> 最后校准:2026-10-23
|
||||
> 代码基线:`dev @ cd9bb141 + 财务 108–112`
|
||||
> 代码基线:`dev @ a7f60414 + 财务 108–113`
|
||||
> 依据:业务口径「人工块当前不以 SLA 监管为目标,先把流程搞清楚:哪个客服处理了哪些东西、付了多少钱、什么项目、关联哪个订单」。
|
||||
> 数据来源:本地只读克隆(生产快照,数据截至 2026-10-14)+ 现有代码盘点。
|
||||
> 重要:**客服备用金支出已经实施**(`manual_expenses`);**公司人工支出登记**(`manual_expense_records`)也已实施,两张表通过 `fund_expense_id` 关联,不是同一张表。
|
||||
|
||||
@@ -124,7 +124,7 @@ P0 四张表即可。
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| id | 主键 |
|
||||
| account_no | 账户编号,唯一 |
|
||||
| account_no | 账户编号,唯一;格式 `FA-<大写用户名>`(如 `FA-KF_2`、`FA-JIAJIALI`),重名追加 `-2`、`-3`;迁移 `113` 已回填历史随机编号 |
|
||||
| account_type | `supervisor` / `agent` |
|
||||
| owner_admin_user_id | 主管或客服的后台用户 ID |
|
||||
| owner_name | 姓名快照 |
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
# 成本中心与三块履约模型
|
||||
|
||||
> 状态:**现行(P0 已实施)**。商品主数据、渠道映射、成本中心、成本快照运行层、销售事实与公司人工支出登记(含订单页逐单实际金额「人工录单」)已落地;轻量人工 case 与影子总账仍为后续方案。
|
||||
> 最后校准:2026-10-22
|
||||
> 代码基线:`dev @ 7c883207 + 财务 108–112`
|
||||
> 最后校准:2026-10-23
|
||||
> 代码基线:`dev @ a7f60414 + 财务 108–113`
|
||||
> 数据基线:2026-10-17 生产库只读聚合(`default_transaction_read_only=on`,仅 SELECT,无写入)
|
||||
> 实施顺序以 [README.md](README.md) §三 为准;本文负责“商品、成本、销售事实”的数据模型,不重复总账与页面设计。
|
||||
> 关联:
|
||||
|
||||
Reference in New Issue
Block a user