feat(finance): 人工履约 SKU 配置清单 + 四钱包(南航/乐玩/ROCK积分 + 备用金现金)

客服人工履约有四个钱包,成本与渠道在后台配置好,客服确认履约时零输入。

口径(2026-10-24 确认):
- 四个钱包:南航积分 / 乐玩积分 / ROCK 积分 / 备用金现金。三平台积分互不通用,
  每客服每平台一个积分账户;现金复用现有 fund_accounts / fund_entries。
- 积分换算率按平台不同:南航 1 积分 = 1 分,乐玩 1 积分 = 1 分,
  ROCK 1 积分 = 1 元(100 分)。真源是履约档案 config_json.rechargeUnitPriceFen。
- 积分是货币,幸运币是商品;消耗积分与成本金额按换算率一一对应。
- 配置主键是**内部 SKU**(快手 spec_json.skuNick / 拼多多 spec_json.outSkuSn),
  不是商品标题(标题是引流)。同名 SKU 算同一商品,跨渠道共用一份配置。
- 配置链路没有匹配引擎、没有打分:扫描 → 配置 → 重新匹配。
  10 月口径下人工单 17,469 单 / 357 个内部 SKU,Top 50 覆盖 88% 单量。
  更早的老单没配置意义,不纳入统计口径。
- 消耗积分填 0 = 成本不固定,客服在确认履约时手填实际成本;
  渠道始终提前配好,客服不选。

迁移 110:
- manual_sku_registry:扫描到的内部 SKU 登记表(统计 + 配置状态)。
- manual_fulfillment_configs:内部 SKU → 渠道 + 消耗积分 + 成本模式。
- platform_credit_accounts / platform_credit_entries:三平台积分钱包与流水。
- order_items.fulfillment_config_id:订单项挂配置,重新匹配时回填。
- 4 条 manual_* 履约档案(manual_dispatch 执行器 + config_json 区分平台)。
  不复用 kuaishou_ct_assisted / kuaishou_feifei——那是已下线的历史自动发货通道。

性能:spec_json->>'skuNick' 无索引时扫描 2.4s / 回填 5.4s;
新增 idx_order_items_manual_internal_sku 表达式索引后回填降到 1.7s。

后端:manual-fulfillment-config-service.ts(扫描/清单/配置CRUD/重新匹配),
成本中心挂 7 个接口。
前端:成本中心新增「人工 SKU 配置」Tab(扫描、清单、配置弹窗、重新匹配)。

校验:后端 765 项 / 0 失败(含 check:sql 迁移护栏),前端 143 项全通过;
E2E 实测扫描 357 个 SKU、配置四平台换算正确、重新匹配回填 7,604 个订单项;
本地库迁移 110 执行后数据量与改造前一致。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
yml2213
2026-10-24 13:12:46 +08:00
co-authored by Claude Opus 4.5
parent fb679d76f6
commit 4bcb4e6b57
7 changed files with 1693 additions and 0 deletions
@@ -11,6 +11,12 @@ import type {
CostPreview,
CostVersion,
CostVersionListResult,
ManualFulfillmentConfig,
ManualPlatformOption,
ManualRematchResult,
ManualSkuListResult,
ManualSkuOverview,
ManualSkuScanResult,
ProductCatalogItem,
ProductCatalogListResult,
TemplateProductBootstrapPreview,
@@ -221,3 +227,59 @@ export function createAdminCostSnapshot(payload: Record<string, unknown>) {
exceptionCreatedCount: number
}>('/api/v1/admin/cost-center/snapshots', payload)
}
/**
* 人工履约 SKU 配置:扫描 → 配置 → 重新匹配。
* 配置主键是内部 SKU(快手 skuNick / 拼多多 outSkuSn),同名 SKU 算同一商品。
*/
export function fetchAdminManualSkus(
params: {
page?: number
pageSize?: number
keyword?: string
status?: 'configured' | 'unconfigured' | ''
platformKey?: string
provider?: string
} = {},
) {
return apiGet<ManualSkuListResult>('/api/v1/admin/cost-center/manual-skus', params)
}
export function fetchAdminManualSkuOverview() {
return apiGet<ManualSkuOverview>('/api/v1/admin/cost-center/manual-skus/overview')
}
export function fetchAdminManualPlatforms() {
return apiGet<{ items: ManualPlatformOption[] }>('/api/v1/admin/cost-center/manual-platforms')
}
export function fetchAdminManualConfig(skuKey: string) {
return apiGet<ManualFulfillmentConfig | null>(
`/api/v1/admin/cost-center/manual-configs/${encodeURIComponent(skuKey)}`,
)
}
export function scanAdminManualSkus(payload: { fromDate: string; toDate: string }) {
return apiPost<ManualSkuScanResult>('/api/v1/admin/cost-center/manual-skus/scan', payload)
}
export function saveAdminManualConfig(payload: {
skuKey: string
platformKey: string
creditQuantity: number
canonicalProductId?: number | null
enabled?: boolean
note?: string
}) {
return apiPost<ManualFulfillmentConfig>('/api/v1/admin/cost-center/manual-configs', payload)
}
export function deleteAdminManualConfig(skuKey: string) {
return apiDelete<{ skuKey: string; deleted: number }>(
`/api/v1/admin/cost-center/manual-configs/${encodeURIComponent(skuKey)}`,
)
}
export function rematchAdminManualFulfillments(payload: { skuKey?: string } = {}) {
return apiPost<ManualRematchResult>('/api/v1/admin/cost-center/manual-configs/rematch', payload)
}