# 变更审计记录:到手金额口径修复(全小程序统一) | 字段 | 值 | |------|-----| | 日期 | 2026-03-26 02:48:42 | | Prompt-ID | P20260325-090826 | | Session-ID | 0ef5e906 | | Session 路径 | docs/audit/session_logs/2026-03/25/24_e10246a9_090825 | ## 操作摘要 修复小程序全场景"到手金额"计算口径。原实现使用 `ledger_amount`(毛收入,未扣抽成),标注"到手"但实际不是到手。修复后统一为:`hours × net_rate`,其中 net_rate 从 DWS 层 `v_dws_assistant_salary_calc` 获取抽成参数计算: - 基础课:`base_course_price - base_deduction` - 激励课/超休课:`bonus_course_price × (1 - bonus_deduction_ratio)` 验证:小燕×轩哥 3月10日 → 毛收入 ¥154.94 → 到手 ¥134.00(1.117h × 120)✓ ## 影响范围 | 文件 | 函数/方法 | 变更类型 | |------|-----------|----------| | `apps/backend/app/services/fdw_queries.py` | `get_service_records()` | 修改 | | `apps/backend/app/services/fdw_queries.py` | `get_service_records_for_task()` | 修改 | | `apps/backend/app/services/fdw_queries.py` | `get_coach_service_records()` | 修改 | | `apps/backend/app/services/fdw_queries.py` | `get_service_records_90days()` | 修改 | | `apps/backend/app/services/coach_service.py` | `get_coach_detail()` | 修改 | ## 技术方案 ### SQL 层(fdw_queries.py 四个函数统一改法) 每个查询新增 `LEFT JOIN app.v_dws_assistant_salary_calc sc`,按 `assistant_id` + `salary_month`(`date_trunc('month', create_time)::date`)关联。`income` 字段从原来的 `sl.ledger_amount` 改为 CASE 表达式: ```sql CASE WHEN sl.skill_name ILIKE '%%激励%%' OR sl.skill_name ILIKE '%%超休%%' THEN (sl.income_seconds / 3600.0) * COALESCE(sc.bonus_course_price * (1 - sc.bonus_deduction_ratio), 0) ELSE (sl.income_seconds / 3600.0) * COALESCE(sc.base_course_price - sc.base_deduction, 0) END AS income ``` ### Service 层(coach_service.py) `get_coach_detail()` 中 `monthly_salary` 从原来的 `gross_salary` 改为 DWS 层已扣抽成的四项之和: ```python "monthly_salary": ( salary_this.get("assistant_pd_money_total", 0.0) + salary_this.get("assistant_cx_money_total", 0.0) + salary_this.get("bonus_money", 0.0) + salary_this.get("room_income", 0.0) ) ``` ## 风险评估 - `salary_calc` 无当月数据时 `COALESCE` 回退 0(到手=0),但这种情况说明 DWS 未跑完,属于数据质量问题而非代码 bug - `LEFT JOIN` 不会导致行膨胀(salary_calc 按 assistant_id + salary_month 唯一) - `get_service_records_90days()` 的 SUM 聚合也已同步改为到手口径 ## 本次对话文件变更 ### 删除的文件 - `docs/audit/session_logs/2026-03/25/19_e69c9fee_040048/main_01_c847b139.md` ## 改动注解 ### `apps/backend/app/services/fdw_queries.py` - 变更类型:修改 - 原始原因:服务记录列表和绩效页顶部卡片使用 `ledger_amount`(毛收入,未扣抽成),标注"到手"但实际不是到手金额。用户反馈 60 天内服务记录列表中到手金额计算不对。 - 思路分析:在 SQL 层通过 `LEFT JOIN v_dws_assistant_salary_calc` 获取每月的课程定价和抽成参数,用 CASE 表达式区分基础课和激励课/超休课两种费率计算方式。选择 `LEFT JOIN` 而非 `INNER JOIN` 确保 salary_calc 缺失时不丢失记录(COALESCE 回退 0)。四个查询函数(`get_service_records`、`get_service_records_for_task`、`get_coach_service_records`、`get_service_records_90days`)统一改法,保证全小程序口径一致。 - 修改结果:所有服务记录列表页面的 `income` 字段现在返回真正的到手金额。影响页面:绩效页服务记录、任务详情页服务记录、助教详情页服务记录、常客统计(90天聚合)。 ### `apps/backend/app/services/coach_service.py` - 变更类型:修改 - 原始原因:绩效页顶部卡片的 `monthly_salary` 使用 `gross_salary`(毛收入),与行级到手金额口径不一致。 - 思路分析:DWS 层 `salary_calc` 已经提供了扣抽成后的分项金额(`assistant_pd_money_total`、`assistant_cx_money_total`、`bonus_money`、`room_income`),直接求和即为到手总额,无需重复计算抽成逻辑。 - 修改结果:绩效页顶部卡片的月收入数字与行级服务记录的到手金额口径统一。 ### `apps/admin-web/src/__tests__/tabUrlSync.property.test.tsx` - 变更类型:修改(非高风险,简要注解) - 与本次到手金额修复无关,属于同一 commit 范围内的其他变更。 ## DDL/迁移检查 - 无新增迁移 SQL - DDL 基线状态:未更新(⚠️ DDL 基线待合并) ## 合规检查 - `api_changed`: false — 接口签名未变,仅返回值语义修正 - `openapi_spec_stale`: false — 无需重新导出