# 抗遗忘工资与工资结算 ## 业务口径 每条计划复习任务仅在计划当天(北京时间自然日)首次完成奖励 1 元,归属任务绑定的复习老师。重复学习不限制;重复完成不新增奖励,也不改写首次完成时间、老师或收入月份。月份使用 Asia/Shanghai。不同计划日期的任务分别处理;逾期允许补做但生成零元 ineligible 凭据,未来任务不允许提前完成。 历史已完成记录生成零金额 `historical` 凭据,异常数据生成零金额 `exception` 凭据,均不自动补发。上线时尚未完成的任务按实际服务器完成日判定 earned/ineligible;完成日不使用手机或传入日期。上线后新导入且已经完成的记录仍视为历史待核对。 ## 数据与接口 - `ReviewReward` 是 SQL 专用不可变账本,不注册为开放的 Parse class。按帐套与任务 objectId 唯一;有效奖励另按来源计划唯一。快照包括老师、学生、门店、课程、计划日期、完成时间和金额。 - 数据库触发器在复习状态更新的同一事务中写凭据;任何写入失败都会回滚完成状态。旧 `content_update` 的 Model 60 完成动作调用 `xiaoshu_complete_review`,只接受 `fxzt=1` 与兼容的 `wcsj` 字段,实际完成时间由数据库决定。 - 任务来源身份为学生、来源学习记录与计划日期,保存在 `rewardTaskKey`;既有重复记录保留并全部标记异常,为该来源保留唯一身份,禁止继续重复生成。 - `PayrollLine.kind` 新增 `review_reward`,携带 `reviewRewardId/reviewTaskId/plannedDate`;数据库校正金额及归属快照,拒绝历史或异常奖励,唯一约束防止跨批次重复计薪。已审核工资及其明细不可改写或删除。 - 工资汇总新增 `reviewCount/reviewAmount`;课次与工时只计算课酬明细。工资批次同时计算课酬、奖励和调整,未结算旧月份的有效奖励可进入后续月份批次。 - `ops/payroll/review-rewards` 支持 `month/storeId/coachId/search/status/page/pageSize`。状态为 earned/historical/exception/ineligible,incorrect 用于筛选逾期错计待核对,返回 items、total 和筛选范围汇总。无法确定收入月份的异常记录始终显示,避免漏掉。 - 老师端 `e_get_21list` 的金额、`e_get_21list_tj` 的收入总额及账户首页读取同一账本。收入合计包含有效奖励,不代表已实际发放。 ## 发布顺序 2026-10-15 本轮升级使用 [老师收入交付说明](teacher-earnings-2026-10-15.md) 的组合迁移,不单独运行以下旧版迁移流程。 1. 备份数据库,确认现有 PayrollBatch 每帐套每月没有重复批次。出现重复会使迁移事务失败,不会静默删除数据。 2. 使用已有部署环境凭据执行 `npm run review-rewards:migrate -- --apply`。不传 --apply 只显示说明。脚本登记新增 Payroll 字段,在一个 SQL 事务中回填历史证据、安装索引和触发器;重复执行不会补发。临时管理员及迁移函数会在 finally 清理,清理失败明确报出 ID。 3. 发布 app gateway 与两个 ops gateway(`scripts/deploy-admin-functions.mjs --only=...`),然后发布移动端和管理后台构建。只更新 app gateway 而未执行迁移时,完成复习会失败,不能跳过数据库前置步骤。 4. 使用授权测试账号验证:计划当天首次完成 1 元、逾期首次完成 0 元、第二次完成返回原凭据;老师端与后台一致;工资草稿刷新不新增同一奖励。核对真实业务完成记录及历史待核对总数,再启用正式结算。 数据库迁移是计薪启用时点。历史核对和补结需单独确认;本模块不提供未经核对的批量补发。代码回退时保留数据库凭据和防重约束,不删除账本来恢复旧版。 ## 验证 `npm run test:review-rewards` 使用 PGlite 执行真实 PostgreSQL DDL、触发器、唯一约束和事务回滚,并运行网关汇总函数。覆盖重复迁移、重复提交、跨月改写、独立任务、重复来源、缺失老师/来源、失败回滚、跨批次唯一、锁定与租户隔离。PGlite 单连接下的并发请求会排队,不等同于生产多连接负载验证。 `npm run test:admin:ci` 包含奖励列表筛选、历史展示、请求乱序和错误反馈测试;另运行移动端测试、双端构建与 cloud:validate。测试成功不代表生产迁移或真实工资发放已验证。 ## 2026-10-15 调整凭据 `ReviewRewardCorrection` 为按原凭据唯一的不可变调整账本;`ReviewRewardIncome` 为原金额加已确认纠正的统一收入视图。原始 ReviewReward 不覆盖。未结算错误来源被阻止结算;草稿中已有错误行同步移除;已审核/已发放保持原件,必须指定另一份带版本的草稿承接 -1 元调整。调整凭据、调整行和审计同事务,重复提交不重复扣减。 经理通过 `ops/payroll/review-rewards/correct` 逐条提交核对依据。页面、导出保留原金额、调整金额、原因和承接工资单。该入口没有批量自动纠正行为。旧 Model 60 完成入口与新 `app_review_complete` 共用数据库完成规则。