From 22605f4106bbc49cae0da29d2252b9df8df4e5f4 Mon Sep 17 00:00:00 2001 From: liuwenxin <1009266660@qq.com> Date: Tue, 3 Nov 2026 11:21:46 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E9=A1=B9=E7=9B=AE):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E9=9C=80=E6=B1=82=E6=96=87=E6=A1=A3=E4=B8=8E=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 收录 2026-11-02 需求补齐计划、验收记录与业务口径时间线 - 新增授权使用、监控运维与产品提取操作说明 - 归档 T+ 前置计划与待确认事项,清理过期临时文档 - README 同步当前进度与权限改造说明 影响范围:仅文档,无代码变更 --- README.md | 9 +- docs/SQLServer2008R2测试环境.md | 68 ----- docs/T+交付部署设计_2026-10-28.md | 40 --- ...+同步页面改造与验收_2026-11-02.md | 57 +++++ ...T+对接待确认事项_2026-10-28(1).xlsx | Bin 0 -> 16501 bytes ...…¥设计_staging到业务表_2026-10-28.md | 148 ----------- docs/T+本地恢复与同步开发手册.md | 40 +++ ...Š¡核算待确认事项_2026-10-28(2).xlsx | Bin 0 -> 13608 bytes ...„则时间线与当前口径_2026-11-02.md | 82 ++++++ ...–与人员岗位操作说明_2026-11-02.md | 49 ++++ docs/内部开发任务表_2026-10-28.xlsx | Bin 0 -> 10224 bytes ...–与样本核对开发记录_2026-10-30.md | 71 ----- ...¸对_辽宁兴晟达_2026-07_2026-11-02.md | 84 ++++++ ...…确认事项表_2026-10-28_客户版.xlsx | Bin 15758 -> 0 bytes docs/客户补充回执核对_2026-10-30.md | 33 +++ docs/客户需求回复记录_2026-10-30.md | 242 ++++++++++++++++++ docs/待确认事项汇总_2026-10-16.md | 99 ------- ...�管理使用与开发记录_2026-11-02.md | 74 ++++++ .../materials-9395-2026-03.json | 116 +++++++++ .../materials-9395-2026-03.md | 51 ++++ docs/模块页面功能清单_2026-10-13.xlsx | Bin 17189 -> 0 bytes ...£式工资闭环开发记录_2026-10-30.md | 82 ------ docs/系统监控运维说明.md | 59 +++++ ...•ˆ核算业务确认单_2026-10-30(2).xlsx | Bin 0 -> 12704 bytes ...»统功能需规_修订版_2026-11-02.docx | Bin 0 -> 17884 bytes docs/角色授权使用说明.md | 42 +++ ...‚补齐实施与验收记录_2026-11-02.md | 95 +++++++ ...€求补齐流程测试报告_2026-11-02.md | 105 ++++++++ docs/需求规格说明书.docx | Bin 82429 -> 0 bytes ...需求规格说明书_V2.1_2026-10-19.docx | Bin 70587 -> 0 bytes .../2026-10-28-tplus-pre-docker-plan.md | 72 ++++++ .../2026-10-28-tplus-pre-docker-todo.md | 49 ++++ tasks/plan.md | 185 +++++++++---- tasks/todo.md | 159 +++++++++--- tasks/需求补齐计划_2026-11-02.md | 15 ++ 35 files changed, 1527 insertions(+), 599 deletions(-) delete mode 100644 docs/SQLServer2008R2测试环境.md delete mode 100644 docs/T+交付部署设计_2026-10-28.md create mode 100644 docs/T+同步页面改造与验收_2026-11-02.md create mode 100644 docs/T+对接待确认事项_2026-10-28(1).xlsx delete mode 100644 docs/T+数据导入设计_staging到业务表_2026-10-28.md create mode 100644 docs/业务核算待确认事项_2026-10-28(2).xlsx create mode 100644 docs/业务规则时间线与当前口径_2026-11-02.md create mode 100644 docs/产品提取与人员岗位操作说明_2026-11-02.md create mode 100644 docs/内部开发任务表_2026-10-28.xlsx delete mode 100644 docs/同步运维自动化与样本核对开发记录_2026-10-30.md create mode 100644 docs/实际样本核对_辽宁兴晟达_2026-07_2026-11-02.md delete mode 100644 docs/客户待确认事项表_2026-10-28_客户版.xlsx create mode 100644 docs/客户补充回执核对_2026-10-30.md create mode 100644 docs/客户需求回复记录_2026-10-30.md delete mode 100644 docs/待确认事项汇总_2026-10-16.md create mode 100644 docs/权限管理使用与开发记录_2026-11-02.md create mode 100644 docs/样本核对包_2026-10-30/materials-9395-2026-03.json create mode 100644 docs/样本核对包_2026-10-30/materials-9395-2026-03.md delete mode 100644 docs/模块页面功能清单_2026-10-13.xlsx delete mode 100644 docs/正式工资闭环开发记录_2026-10-30.md create mode 100644 docs/系统监控运维说明.md create mode 100644 docs/绩效核算业务确认单_2026-10-30(2).xlsx create mode 100644 docs/衍水绩效管理系统功能需规_修订版_2026-11-02.docx create mode 100644 docs/角色授权使用说明.md create mode 100644 docs/需求补齐实施与验收记录_2026-11-02.md create mode 100644 docs/需求补齐流程测试报告_2026-11-02.md delete mode 100644 docs/需求规格说明书.docx delete mode 100644 docs/需求规格说明书_V2.1_2026-10-19.docx create mode 100644 tasks/archive/2026-10-28-tplus-pre-docker-plan.md create mode 100644 tasks/archive/2026-10-28-tplus-pre-docker-todo.md create mode 100644 tasks/需求补齐计划_2026-11-02.md diff --git a/README.md b/README.md index b5c8edf..1d7ab9c 100644 --- a/README.md +++ b/README.md @@ -137,10 +137,17 @@ python e2e/system_management.py # 系统管理 13 项 ## 正式工资闭环 -- 在现有账号中明确绑定工资制作人:`PAYROLL_MAKER_USER_ID`。未配置时业务只读,不按管理员或岗位自动放行。真实账号绑定需由维护者核实,不在源码或示例中写入实际用户编号。 +- 在“角色管理”配置工资操作权限,在“用户管理”分配角色;账号自动继承权限,无需单独绑定工资制作人。每次实际经办人继续留痕。 - 应用新增迁移后,T+ 页面提供正式业务导入预览/执行;业务列表“正式核算”准备人工业务资料或核算已导入资料,台账可查看逐段依据。 - “生成月结快照”首次成功即锁定该月分配;审批退回、重新生成不解锁。历史已生成工资保留,差额计调整单生成当月。 - 后端接口说明、验证状态和已知边界见 `docs/正式工资闭环开发记录_2026-10-30.md`。旧引擎仅通过 `PAYROLL_ALLOW_LEGACY_CALCULATION` 显式启用作历史兼容,默认关闭,不用于最新规则验收。 - 集成回归使用 `scripts/run_isolated_tests.py`;原 `.venv` 不可用时,本机使用 `backend/.venv-workbench/Scripts/python.exe`。测试运行器保留隔离库供复查,不删除原开发数据。 审核默认关闭:`PAYROLL_APPROVAL_ENABLED=false`,工资生成直接完成且不产生审批痕迹;如确需系统内复核,显式开启后沿用财务/领导审核和各类审批参数。此配置与旧核算引擎兼容开关独立。 + +## 权限管理 + +- “用户管理 → 分配角色”:选择角色并预览继承权限,支持多个角色叠加。 +- “角色管理 → 配置权限”:按模块配置模板;停用角色即时撤销其授权。 +- 管理员拥有全部功能权限;月份锁定、审核节点及源读取开关继续独立检查。 +- 授权变更无需重新登录,后端逐请求校验;详情、只读提示、菜单与按钮使用统一规则。操作与接口说明见 [权限管理使用与开发记录](docs/权限管理使用与开发记录_2026-11-02.md)。 diff --git a/docs/SQLServer2008R2测试环境.md b/docs/SQLServer2008R2测试环境.md deleted file mode 100644 index e9daf06..0000000 --- a/docs/SQLServer2008R2测试环境.md +++ /dev/null @@ -1,68 +0,0 @@ -# SQL Server 2008 R2 测试环境与验收手册 - -> 目标:在真实 Windows + SQL Server 2008 R2(10.50.x)环境中恢复客户原始备份,完成同版本兼容验收,关闭「2008 R2 状态 PENDING」。本手册在取得合法安装介质后即可照做;介质到位前的准备工作只做第 2、3 节中不依赖介质的部分。 - -## 1. 背景与当前状态(2026-10-28) - -- 客户源备份 `ceshi20261026.bak` 版本为 10.50.1600。按用户 2026-10-28 决定,先以该版本搭建开发验收环境;生产完整版本号后补,有差异时再核验(客户版 E01/E03)。 -- 本地 Docker 已用 SQL Server 2022 副本完成恢复 PoC:完整 CHECKDB 通过、只读账号可用、六类查询两轮核验 933,203 行无失败。该副本只用于结构核验与开发,**不能替代同版本验收**。 -- Hyper-V 虚拟机外壳已建于 `D:\work\app\tplus-vm`,处于关机、断网状态;Windows 与 SQL Server 2008 R2 安装介质尚未到位(客户版 E03)。 - -## 2. 环境约定 - -| 项目 | 约定 | -| --- | --- | -| 虚拟机目录 | `D:\work\app\tplus-vm` | -| SQL Server 数据与日志 | 2022 PoC 使用 `D:\work\app\tplus-sqlserver\data` 和 `log`;2008 R2 使用 D 盘虚拟磁盘内的来宾目录,恢复时确认实际路径 | -| 备份文件 | 现有脚本使用 `D:\work\app\tplus-sqlserver\backup`;复制到虚拟机前后核对 SHA-256 | -| 虚拟机网络 | 安装与验收期间保持仅主机或内网隔离,不接入公网 | -| 凭据 | 只读账号凭据走双方认可的私密渠道交接;不写入本文档、代码或 Git | -| 项目依赖脚本 | `scripts/tplus/`(工作区准备、备份检查、恢复、只读账号、结构盘点) | - -客户版 E01 先使用本地恢复实例的连接信息和专用只读账号,E02 先用现有开发主机与网络,生产信息后补。E03 的目标版本已确定,但合法介质尚未到位,不能据此把安装或验收标为完成。 - -## 3. 装机步骤(依赖介质,介质到位后执行) - -1. 通过 Hyper-V 管理器核对已有虚拟机与 D 盘磁盘位置,保持网络隔离。`prepare_sql2008r2_vm.ps1` 是创建脚本,已有同名虚拟机时拒绝覆盖,不用于状态检查。 -2. 准备适配 SQL Server 2008 R2 的合法 Windows 介质,安装来宾系统。记录系统版本及补丁,不把来宾系统版本当作未来工资部署主机的要求。 -3. 安装 SQL Server 2008 R2,基准锁定为 `10.50.1600`。排序规则从备份元数据或恢复库核验,不能凭文档默认值猜测。 -4. 首轮保留该基准;如后续需要测试 SP3 等其他补丁,另记版本和结果,不覆盖基准验收记录。 -5. 在运行后端/worker 的电脑上准备 ODBC 驱动。驱动、Windows 和 TLS 的实际组合须实测后记录,不能只根据驱动名称认定兼容。默认启用加密,隔离环境的显式回退步骤见本地开发手册。 - -## 4. 备份恢复步骤 - -现有备份检查、恢复、创建只读账号及盘点脚本调用 Docker 容器,使用容器内路径,仅适用于 2022 PoC。2008 R2 在虚拟机中按以下步骤操作,不直接套用容器脚本。 - -1. 在来宾系统中复制原始备份,核对文件哈希;由测试环境管理员通过数据库管理工具执行备份验证并读取文件列表,记录实际数据/日志逻辑名。 -2. 恢复到新的测试数据库,在恢复界面为每个逻辑文件指定来宾磁盘路径;确认目标库不存在,不覆盖其他数据库。 -3. 恢复后执行完整数据库一致性检查并留档;记录版本、排序规则和恢复数据库名。 -4. 创建仅用于该测试库的登录和用户,授予读取权限,核对角色、显式授权和禁止写入的结果。恢复/建账号使用管理员,应用始终使用专用只读账号。 -5. 对照 `db/queries/tplus/` 的九类实体查询和关联核验查询盘点结构、行数及汇总金额;保留差异原因。报告不包含凭据或个人明细。 - -## 5. 同版本验收清单(逐项通过后关闭 PENDING) - -| # | 验收项 | 通过标准 | -| --- | --- | --- | -| 1 | 版本确认 | `SERVERPROPERTY('ProductVersion')` 为 10.50.1600(末尾 .0 等价);其他 10.50 补丁版本单独记录,不能冒充基准通过 | -| 2 | 驱动连接 | 从实际运行后端的电脑连接成功,记录驱动名称、版本与加密/证书设置 | -| 3 | 只读权限 | 用只读账号执行六类查询成功;执行任何写操作被拒绝 | -| 4 | 六类查询 | 人员、客户、产品、订单、发货、收付款九个白名单 SQL 全部返回,行数与 Docker 副本一致 | -| 5 | 中文数据 | 姓名、客户名、产品名等中文字段读取无乱码(只读账号仅验证读取) | -| 6 | 日期字段 | 凭证日期、审核日期、到账日期等候选字段格式与空值表现正常 | -| 7 | 金额精度 | 金额字段以 Decimal 读取,小数位与源数据一致 | -| 8 | 断连超时 | 仅在隔离测试实例模拟断连;批次不得误报成功,批次失败或行级错误可追溯,恢复后可重试 | -| 9 | 重复同步 | 同一备份重复 staging,相同行哈希全部去重跳过,行数不变 | -| 10 | 关联核验 | `relationship_audit` 数量统计与 Docker 副本结果一致 | - -## 6. 产出与归档 - -- 验收通过后产出报告(含上表逐项结果与 `@@VERSION` 输出),归档至 `.ai/archive/ai-aux/`;项目文档更新结论为「2008 R2 验收通过」。 -- 同步更新 `.ai/AI_CONTEXT.md` 与 `.ai/PROJECT_PROGRESS.md`。 -- `check_compatibility.py` 默认核对 10.50.1600,复用应用连接策略;它的脚本检查通过不能替代本表中的断连、重复同步及完整权限验收。 -- 验收中发现的字段差异回到 `docs/客户待确认事项表_2026-10-28_客户版.xlsx` 对应编号,不直接改代码。 - -## 7. 明确边界 - -- 本环境仅验收 T+ 源库只读访问;工资系统生产部署(客户版 E02)另行确认。 -- 客户生产 T+ 原库不升级、不改动;2022 副本不回迁。 -- 时间增量(确认单 #13)不在本手册范围内,待 rowversion 验证方案另行评审。 diff --git a/docs/T+交付部署设计_2026-10-28.md b/docs/T+交付部署设计_2026-10-28.md deleted file mode 100644 index 2ae2d47..0000000 --- a/docs/T+交付部署设计_2026-10-28.md +++ /dev/null @@ -1,40 +0,0 @@ -# T+ 交付部署设计(2026-10-28) - -状态:设计稿。本文约定后续 D1/D2 的实现方向;本轮没有安装服务、创建计划任务或发送告警。 - -## 托管方案 - -| 方案 | 适用方式 | 本项目取舍 | -| --- | --- | --- | -| Windows 任务计划程序 | 启动时运行现有 worker,设置失败重启和禁止重复实例 | 首期推荐;复用现有 CLI,不增加第三方服务包装依赖 | -| NSSM | 将长驻进程包装为 Windows 服务 | 如客户要求服务管理器统一管理,再评审安装来源与版本;本轮不引入 | -| 原生 Windows 服务包装 | 开发服务生命周期、停止信号和恢复逻辑 | 当前缺少此实现,首期维护成本较高,暂不选用 | - -开发环境先围绕备份源 `10.50.1600` 验证连接;工资后端继续使用现有开发主机与 Python 环境。数据库来宾 Windows 的版本不能用来推断工资部署主机的版本。生产主机、服务账号与目录由 客户版 E02 回填后确定。 - -后续托管任务采用启动触发,工作目录指向部署包 `backend/`,直接运行部署虚拟环境中的 `python.exe -m app.cli tplus-worker --watch`。不要在托管任务启动时执行依赖升级。账号仅授予所需目录、日志和私有配置访问权限;凭据不作为任务命令行参数。 - -建议恢复参数:进程异常退出后间隔 1 分钟重启,最多 3 次;同一任务已有实例时忽略重复启动;持续运行的 worker 不设通用执行时长上限。三次失败后转人工处理。以上是设计默认值,未写入客户环境。 - -## 每周排队与重试 - -拟新增单独的排队命令,调用现有 `task_service.create_task`。每周一 02:00(Asia/Shanghai)排队一次全量暂存,时间待业务方确认;尚未验收的时间增量保持关闭。worker 仍只消费队列,两者职责分开。 - -排队命令按“源账套 + ISO 周 + 任务类型”生成稳定 UUID 请求键,重复触发复用同一任务;排队时若同账套有活动任务,先记录本周待补状态,结束后再补排,避免队列堆积。停机后补跑一次,不逐周补发过期任务。 - -业务任务失败与进程退出分别处理。暂定仅对可确认的断连、连接超时重试,间隔 5 分钟、15 分钟,最多 2 次;每次调用现有重试接口,保留父批次。配置错误、版本不符、字段缺失、类型未确认及 PARTIAL 转人工处理。当前错误码可能合并为 `EXECUTION_ERROR`,D2 实现时先补可测试的错误分类,不能据此宽泛自动重试。 - -## 告警与观察 - -管理员同步页面与脱敏日志作为首期查看入口。拟对 FAILED/PARTIAL、连续 3 次进程重启失败、QUEUED 超过 15 分钟以及超过 8 天没有成功同步提示异常。运行时长阈值需在同版本首轮全量耗时实测后确定。 - -外部邮件或企业消息通道、接收人、网络出口待 客户版 E02 与客户答复,当前不配置也不发送。通知内容限批次号、状态、时间、错误码和处理入口,不包含凭据、手机号或原始 JSON。相同根批次和错误码 30 分钟内合并通知,恢复成功发一次恢复通知;投递失败保留记录,不改变同步批次结果。 - -## 实施与验收顺序 - -1. 先完成备份源同版本 A3;确认业务规则并完成 C2–C5 后,再启用正式托管和自动排队。开发阶段可用隔离数据库模拟调度行为。 -2. D1 验证重启后启动、异常退出恢复、重复触发单实例、受限账号读配置、停止后不领取新任务、升级与回退均能重新取得锁。 -3. D2 验证重复周任务、停机补跑、断连重试次数、PARTIAL 人工处理、通知去重与投递失败。不得用模拟成功代替真实同版本验收。 -4. 发布时先手动单批运行并对账,再启用周任务。异常时停用排队与 worker,保留批次和原始数据,回退应用版本;不清空业务数据。 - -待填内容:客户版 E01 的生产连接、账号和版本差异,E02 的部署主机、网络、同步时段和通知方式,E03 的同版本介质,E04 的工资验收例单,以及 S1 的生产敏感字段策略。没有这些答复时继续文档与隔离开发验证,不虚构生产配置。 diff --git a/docs/T+同步页面改造与验收_2026-11-02.md b/docs/T+同步页面改造与验收_2026-11-02.md new file mode 100644 index 0000000..0ba4313 --- /dev/null +++ b/docs/T+同步页面改造与验收_2026-11-02.md @@ -0,0 +1,57 @@ +# T+ 同步页面改造与验收 + +## 需求与范围 + +用户要求重新核对同步需求、在页面提供自动采集开关、重做功能布局与 UI,并显示自动更新的真实进度条。 + +原始依据:`问题与解决方案对照表_v2.xlsx` 第 10 项为每周同步并支持手动触发,第 27 项为日志和失败重试;开发计划的 T+ 同步模块要求按类别读取、去重、人工字段保护与异常可追溯。当前源为本地 Docker 恢复库,源库只读;采集不自动生成工资。 + +## 本次执行约定 + +- 自动采集开关按源连接身份保存到本系统 MySQL,复用 `tplus:collect` 权限及操作日志;维护进程每次检查都读取保存值,不靠前端记忆或改写服务器环境文件。首次未保存时沿用环境配置,保留当前已开启状态。 +- 关闭开关阻止后续自动排队及自动重试,不中断已排队或正在执行的任务,不影响手动同步。开启后按现有每周一 02:00、停机只补最近周期与同周防重规则执行。 +- 采集前统计所选类别的真实行数,逐页提交已处理数、当前类别和更新时间。统计失败或旧任务没有总量时,显示不确定进度及已处理条数;不生成假百分比,不将“全部读取完但有异常”显示为成功。 +- 当前进度、任务记录及打开的详情会自动更新;后台更新保持内容可见,页面隐藏或离开后停止重复请求,失败时保留上次数据并提示。 +- 保留同步记录、错误定位、失败重试、关联检查及资料导入能力。主页面按“当前同步、自动采集、同步记录”排序,资料与导入及关联核查分标签展示。 + +## 设计决定 + +采用 `design-taste-frontend` 的 framed-sheet 方向(seed 2069071769),保留项目字体、蓝色品牌及现有全局导航,只改本页。用平面白色分区和细边界组织内容,进度数据使用蓝色,异常使用语义色,不增装饰图表。 + +首屏回答“同步到哪里、是否还在运行、接下来能做什么”。进度是主信息,自动采集开关和排期是侧区,历史批次是可操作列表;手机端按同一阅读顺序单列排列。所有统计取真实接口,不放示例业务数。 + +## 验收条件 + +1. 有权限账号切换开关后,页面、独立维护进程及刷新后的结果一致;无权限写入返回 403,过期配置版本返回 409,失败不伪装保存成功。 +2. 总量统计、逐页进度、完成、失败及未知总量都有可解释状态;真实条数、进度百分比和终态一致。 +3. 同步页与详情自动更新,页面离开后清理定时器,后台刷新不反复覆盖整页加载遮罩。 +4. 在隔离库验证迁移及接口,再在本地开发库应用新增配置表;保留当前全量采集,不清数据、不生成工资。 +5. 后端相关测试、结构检查、前端类型和构建及真实浏览器开关/进度/权限/响应式验证通过。实施前不将这些条件记为已通过。 + +## 实施结果(2026-11-02) + +已完成页面开关、真实进度、自动刷新、详情明细和三档响应式布局。自动开关保存到 `tplus_automation_configs`,按源身份生效;维护进程每次检查读取保存值。关闭开关只停止后续自动排队,活动任务继续;手动同步不受影响。 + +后端新增 `PUT /api/v1/system/tplus/automation`,使用 `tplus:collect` 权限、版本乐观锁和操作日志。批次接口输出受控 `progress` 元数据:总量、已处理、百分比、当前类别、更新时间和分项状态;旧批次或统计失败显示未知总量,不编造百分比。同步总量统计查询位于 `db/queries/tplus/progress/counts.sql`,只统计白名单源表。 + +前端首屏为当前同步进度和同步计划开关;下方“同步记录、资料与导入、关联检查”分区展示。页面运行中每 5 秒刷新,空闲每 30 秒刷新,切离页面停止轮询并清理定时器;后台更新保留已有数据和交互状态。任务详情同步自动刷新,完成后显示终态和分项结果。 + +## 验证结果 + +- 后端单元:916 项通过,包含自动设置、进度、同步、查询、权限冲突和模型表集合。 +- 隔离库集成:25 项通过,覆盖控制台接口、既有管理接口、自动周期与迁移结构;V27 配置表完成降级/升级验证。 +- Ruff、前端类型检查和 Vite 生产构建通过。 +- 本地开发库仅应用 V27 独立建表 SQL;本地 Alembic head 仍受未应用 V26 授权迁移影响,未强行升级。 +- 真实 Edge 页面验证通过:管理员切换开关后独立维护实时读取;关闭后不再排队、刷新保持;开启后可手动创建人员+收付款单任务;真实总量 19,178,页面从 0% 自动推进到处理中数值;1440/768/390 无横向溢出;详情自动刷新;只读账号按钮禁用且接口 403;离开页面停止轮询。 +- 浏览器设计检查无 FAIL;保留全局警告:角色标签对比度已调整、系统仍存在三种字族、表格边框偏重及两卡片高度差,后续视觉统一时处理。 + +## 证据与边界 + +证据在 `.ai/tplus-page-redesign-20261102/`,含浏览器结果、真实进度记录、隔离测试、本地配置表前后计数与源总量统计。本轮只读源库、只保存采集与展示层数据;未导入正式业务、未生成工资、未连接生产、未提交或推送。 + + +## 2026-11-02 任务详情去重与分项口径更新\n +- 创建/重试后不再自动弹出详情,页面显示提交提示和“查看已提交任务”入口,保留当前标签页。 +- 详情移除与主页面重复的大进度卡,改为任务来源、创建/开始/结束时间、汇总结果、分项读取明细、异常和关联检查报告。若详情任务不是主页面当前任务,会明确提示两者不同。 +- 分项进度缺失时不再显示 0;接口返回空值并由界面显示“未记录”。真实分项进度仍按实际条数展示,正在执行任务详情每 5 秒更新,关闭后停止该详情轮询。 +- 相关单元 66 项通过;Ruff、前端类型检查和构建通过。模拟接口浏览器 5 组场景通过,真实任务只读验证通过;截图与结果 `.ai/tplus-detail-browser/`、`.ai/tplus-detail-live/`。本轮只做展示层验证,未创建或重试真实采集任务,未操作生产或生成工资。 diff --git a/docs/T+对接待确认事项_2026-10-28(1).xlsx b/docs/T+对接待确认事项_2026-10-28(1).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7c4b5a0125f88b244469206eab8b25b2d7ac9e28 GIT binary patch literal 16501 zcma)jWmFhT(l+iM+}$05LvRT0?(Xgo+}+(>0>Rzg-QC@T>qqY0-McsM?w+rI%*>go zr>ncVyQaHNJu>3JAW#6mN|4kx@2~qm3*^UxfwjJjowbcUoy>A|rN04445q@ZR?Vp&BKvUMrfBiBQXi$VqmsD1`|#`71wC z(7Xu34~XOLh_GDFF3GCdhNEIm?Jf!M3Hb{{E?&EKCS|JACr%rhhXKLYQ{@

Pl^>AKIH|7l~?b^TnkxanY1U9?k$68nPE}T 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 J_Hq5f{Xg 状态:设计稿,未实现。客户确认单(`docs/客户待确认事项表_2026-10-28_客户版.xlsx`)业务口径答复齐全并完成设计评审后,再实现导入。「预留参数」在本稿中表示待确认决策,不代表已建系统设置项;字段映射、流程规则、部署配置须分别回填。 - -## 1. 目标与边界 - -- 将 `tplus_sync_records`(staging)中 PENDING 的原始行,按映射规则写入六类工资业务表:人员 `personnel`、客户 `customers`、产品 `products`、业务 `businesses`(含 `business_items`)、发货 `shipments`(含明细)、回款 `receipts`。 -- 同步链路已具备:批次/错误/水位/锁/重试由现有 `tplus_sync_batches`、`tplus_sync_errors`、`tplus_sync_watermarks` 与 `tplus-worker` 承担;本设计只增加「应用器」环节,不改动现有读取链路。 -- 不在范围内:工资核算、月结、审批(沿用既有模块);时间增量(确认单 #13 闭环前水位保持禁用)。 - -## 2. 总体流程 - -```text -staging PENDING - → 应用器按实体分批读取(entity_type + row_hash) - → 字段映射 + 口径参数校验(含预留参数缺省值) - → 幂等检查(锚点已存在则置 SKIPPED) - → 写业务表(应用层关联,不建物理外键) - → 成功置 APPLIED;失败置 ERROR 并写 tplus_sync_errors -``` - -- 每个实体一个应用器,导入顺序固定:人员 → 产品 → 客户 → 业务(含明细)→ 发货(含明细)→ 回款。上层实体失败时跳过下层并保留 PENDING,供重试。 -- 新增「导入运行记录」需求:每个批次的每个实体记录读取数、写入数、跳过数、失败数(实现时以新表或复用批次审计字段承载,评审时定稿)。 - -## 3. 幂等与锚点 - -- staging 层唯一键 `uk_tplus_sync_records_entity_source_hash`(entity_type + source_id + row_hash)保证重复快照不重复入库。 -- 业务表锚点:订单/发货/回款以 `source_no`(T+ 单据号)幂等;主数据以 `source_id` 幂等。锚点字段在实现时补唯一约束(如 `uk_receipts_source_no`)。 -- 每笔回款只能核算一次:已存在核算记录的回款,重复导入直接跳过,不做金额合并。 - -## 4. 金额与精度 - -- 金额字段一律 `Decimal`;比例、日斜率一律 `Fraction`;全程禁用 float。 -- 业务员计提沿用既定公式:`10‰ − 回款天数 × 4/360‰`,1–360 天线性递减,360 天 6‰,361 天及以上固定 4‰。 -- 毛利润不含运费(9.8 方案蓝色字体原算法作废);混合产品按明细行分别计算;负绩效照算不归零。 -- 多单分批回款的分摊与尾差处理属预留参数(#5),未定前不实现分摊逻辑。 - -## 5. 人工字段保护(T+ 不覆盖) - -| 字段 | 保护方式 | -| --- | --- | -| 人员岗位角色ID | T+ 同步不覆盖,只填新人员缺省角色 | -| 回款批次号 / 发货单号 | `HK…` / `SH…` 系统生成,同步行只记录 source_no 追溯 | -| 业务归属变更 | 只影响变更后的核算,不回溯历史 | -| 客户负责人、客户分类 | 由人工维护,同步不覆盖 | -| 产品计提分类、指导价 | 由人工维护(#11) | -| 回款/发货批次人工指定 | 系统提供人工指定入口,导入只建待指定数据 | - -## 6. 事务与错误边界 - -- 应用器按「批次 × 实体 × 每 N 行」开事务;单行失败不回滚整批,错误行写 `tplus_sync_errors`(含 error_code 与说明)。 -- 批次状态机沿用现有 QUEUED/RUNNING/SUCCEEDED/PARTIAL/FAILED;出现 ERROR 行时批次终态为 PARTIAL。 -- 应用器与 worker 共用 MySQL 连接级锁,避免与读取任务并发写同一批次。 -- 重算必须授权并留痕:已核算数据不允许静默覆盖,重算入口生成带请求人、时间、原因的审计记录(复用操作日志)。 - -## 7. 预留参数清单(等待客户答复) - -本节保留旧编号供开发追溯。当前对外文件为《客户待确认事项表_2026-10-28_客户版.xlsx》,旧表已按用户决定删除;回填时按第 10 节对应关系查找,不重复询问已经确定的规则。 - -| 编号 | 预留参数 | 等待内容 | -| --- | --- | --- | -| #1 | 成本取值 | 订单 LatestCost 与销货 costPrice/costAmount 的取舍(含税 L1 一并确认) | -| #2 | 发货日期口径 | 凭证/发送/交货/审核日的取舍与缺失处理 | -| #3 | 到账日期口径 | 主表时间与明细 arrivalDate 的认定,预收与分次到账 | -| #4 | 无订单回款 | 补录、人工指定或不纳入 | -| #5 | 多单分摊规则 | 分摊方式与尾差对账 | -| #6 | 可计提收款范围 | 期初/预收/退款/费用单的排除与承接 | -| #7 | 有效性与核销条件 | 生效即可计提还是须核销 | -| #8 | 负向事件 | 退货/红冲的冲减月份与重复冲减防护 | -| #9 | 人员口径 | 工号确认、取数范围、经理归属(L6 经理个人户只调参数) | -| #10 | 客户口径 | 往来单位筛选、改名合并 | -| #11 | 产品口径 | 单位换算、价格类型、计提分类维护方 | -| #12 | 收款方式 | 结算方式枚举与以物抵顶差异 | -| #13 | 初始化与增量 | 起始日期、历史已结算款识别、rowversion 验证 | -| L2 | 特殊款项 | 预收、保证金、代收,与 #3/#6 一并确认 | -| L3–L5 | 二次分配三项 | 追认后回填分配标的、余额归属、协助关系 | -| L7 | 三级角色职权 | 页面验收时核对 | -| B1–B5 | 环境接入与介质 | 先用本地备份恢复环境,版本基准 10.50.1600;生产信息后补,介质仍需落实,凭据不入文档和 Git | -| S1 | 敏感字段策略 | 当前开发阶段暂接受未单独加密的风险;生产保留、保护和备份范围仍待确认 | - -## 8. 字段核验备注 - -2026-10-28 用 T+12.3 数据字典(rar)交叉验证了 11 张目标表的关键字段:字典中文名与待确认清单的表述一致,与恢复库实测没有冲突。有两点差异,实现时需要注意: - -- `SA_SaleDelivery.SendDate`(送货日期)是 T+12.3 新增字段。客户生产库版本未确认(B3),应用器读取映射字段前应先检查列是否存在,缺列时写入 `tplus_sync_errors`,不要让批次直接中断。 -- `ARAP_ReceivePayment_b.arrivalDate` 在字典中是「到期日」,不是实际到账日。到账日期口径(#3)确认前,该字段只作候选留档,不参与回款天数计算。 - -字段描述出现文档间分歧时(如存货表 `InvSCost` 仅见于 12.1 说明文档),以恢复库实测为准。 - -## 9. 实现触发条件 - -1. 当前客户版的业务答复足以确定导入规则,并完成对应设计评审(检查点 A);生产地址等资料可在正式联调前补齐。 -2. 本设计按答复修订并评审定稿。 -3. 先实现主数据导入并通过可回滚验收(检查点 B),再进入交易数据与负向事件。 - -开发设计与隔离测试不等待生产地址/账号。备份源同版本环境仍须实际安装和验收;正式上线须补齐生产环境信息并完成 S1 决策。 - -## 10. 口径答复回填清单 - -所有答复先写入当前客户版 F 列,记录答复人、日期、例单或来源,再修订本稿。技术字段存在只能证明可取数,不能代替业务方选择计提口径。旧表问题已归并为下表编号,旧编号仅供内部追溯。 - -| 原编号 | 当前客户版编号 | -| --- | --- | -| #1、L1 | B02 成本取法、B01 含税口径 | -| #2、#3 | T01 发货日、T02 到账日 | -| #4、#5 | T03 回款归属与跨单分摊 | -| #6、L2 | B08 特殊款项 | -| #7、#8、#12 | T04 状态、T05 负向事件、T06 抵顶方式 | -| #9、#10、#11 | T07 人员、T08 客户、T09 产品 | -| #13 | B07 启用与历史承接;增量发现属于开发设计 | -| L3–L5 | B03 分配规则;修改窗口另见 B04 | -| L6、L7 | B05 经理本人业务、B06 岗位权限 | -| B1/M1、B2/M2、B3/M3 | E01 生产连接,E03 备份源版本验收 | -| B4/M4、B5/M5 | E02 部署与同步,E03 同版本介质 | -| S1 | S1 敏感字段策略 | - -客户版 E04 另列实际工资结果核对:先单笔、再个人与部门月结,复用已提供例单并逐笔解释差异。它是正式交付验收项,不能由技术测试代替。 - -| 编号 | 设计回填位置与核验重点 | 定稿后的实现顺序 | -| --- | --- | --- | -| #1 / L1 | 销售额、成本字段,含税口径;用成本调整例单核对 | C3 明细映射与金额校验 | -| #2 | 发货日期及缺失处理,核对 SendDate 实际存在性 | C3 发货导入 | -| #3 / L2 | 到账日期与预收转正式回款;arrivalDate 字典为到期日,不默认作到账日 | C3 回款导入 | -| #4 | 无订单关联数据的人工补录或排除规则 | C3 关联异常处理 | -| #5 | 多单分摊、金额合计、尾差规则 | C3 分摊与对账 | -| #6 / L2 | 期初、保证金、代收和历史已核算款的纳入范围 | C3 回款过滤 | -| #7 | 生效、核销、作废的真实状态对应关系 | C3 有效性校验 | -| #8 | 原单追溯、冲减月份、已结算调整和防重复 | C4 负向事件 | -| #9 | 人员工号、范围、经理关系,保护人工岗位字段 | C2 人员导入 | -| #10 | 客户筛选、改名合并和源 ID 追溯 | C2 客户导入 | -| #11 | 单位换算、价格、指导价与计提分类维护方 | C2 产品导入 | -| #12 | 结算方式枚举与以物抵顶的核算差异 | C3 回款方式 | -| #13 | 初始化起点、历史核算识别、变更/作废/删除发现 | C5 增量方案,验证前不启用时间水位 | -| L3 | 二次分配标的与现有拆行实现的差异 | 校准已有分配逻辑并回归 | -| L4 | 不足 100% 的余额归属与留存方式 | 与 L3 一并校准 | -| L5 | 协助仅记录、不计提的追认 | 核对独立二次分配机制 | -| L6 | 经理个人户客户确认结果 | 核对生效日期后调整既有参数并复核例单 | -| L7 | 角色名称、人员和可操作项 | 权限配置及页面验收 | -| B1/M1、B2/M2 | 开发先用本地只读连接;生产地址和凭据单独交接 | 部署前配置及最小权限检查 | -| B3/M3 | 先按备份源 10.50.1600;生产完整版本后补 | A3 基准验收,再验证生产差异 | -| B4/M4 | 开发现有主机先行;生产系统和网络后补 | D1/D2 托管与告警配置 | -| B5/M5 | 合法介质来源、版本与可用性 | A2 安装后进入 A3 | -| S1 | 人员表、暂存表和备份的保护、访问、保留期 | 全库策略确认后另行实施,上线前验收 | - -- [ ] 核对每项答复与原始附件,冲突仍标待确认,不填猜测默认值。 -- [ ] 补齐源字段到目标字段、空值处理、人工字段保护和幂等映射,评审后定稿。 -- [ ] 按 C2 → C3 → C4/C5 顺序实施,先定点测试与对账,再做隔离回归。 -- [ ] 业务清单、设计、实现和验收结论同步更新;未答复项保留原编号。 diff --git a/docs/T+本地恢复与同步开发手册.md b/docs/T+本地恢复与同步开发手册.md index 4d1e7df..597870d 100644 --- a/docs/T+本地恢复与同步开发手册.md +++ b/docs/T+本地恢复与同步开发手册.md @@ -1,5 +1,37 @@ # T+ 本地恢复与同步开发手册 +## 2026-11-02 自动采集和开发托管(当前状态) + +用户后续要求启用自动采集,本机 `backend/.env` 的 `T_PLUS_AUTOMATION_ENABLED` 已改为 `true`。每周一北京时间 02:00 为应用排队时点;每分钟执行的是 `tplus-maintain --once` 检查,不是每分钟全量采集。首次开启仅补最近一个已到期周期,同周防重,任务占用时延后。 + +Windows 本地开发任务目录为 `\PayrollManagementSystem-Dev\`,新增三项: + +| 任务 | 执行内容 | 触发方式 | +| --- | --- | --- | +| `PayrollDev-backend` | 本机 8000 端口后端 | 当前用户登录,支持手动启动 | +| `PayrollDev-worker` | `tplus-worker --watch` | 当前用户登录,持续消费队列 | +| `PayrollDev-maintenance` | `tplus-maintain --once` | 当前用户登录及每分钟检查 | + +三项复用现有 `scripts/windows/Run-PayrollHost.ps1`,当前用户 Interactive/Limited,隐藏运行、并发 IgnoreNew、失败间隔一分钟最多重启三次;运行目录 `.ai/tplus-dev-connection-20261102/task-runtime/`,日志按次保留。本机需开机且该用户登录;这不是客户生产的无人登录服务部署。未覆盖其他任务,也未保存账号密码到任务参数。 + +管理时可用 `Get-ScheduledTask -TaskPath '\PayrollManagementSystem-Dev\'` 和 `Get-ScheduledTaskInfo` 检查状态与上次结果。维护日志应见 CHECKED/DEFERRED/QUEUED 等结果。关闭自动排队时先停用维护任务并将本地开关关闭,当前采集应完成后再停 worker;不为重启而强停活动采集。删除开发任务需精确指定本目录中上述三项,不触碰客户正式任务。 + +本轮发现原全量批次 `TP20261102150914e2605f90` 曾推进至 306612 条,随后采集进程退出且心跳停止,页面仍保留 RUNNING。恢复 worker 后由现有恢复逻辑记为 FAILED/INTERRUPTED,保留全部证据;退出原因未从日志查明。无需删除批次或重置数据。 + +自动维护已创建 2026-W45 批次 `TP20261102154100c994af25`,按九类全量重新读取并哈希去重,目前仍在执行。重复维护未创建第二个任务,当前无需再手动重试原批次。真实接口和页面均显示自动采集已开启;最终全量成功必须待本批次结束后单独记录。 + +## 2026-11-02 开发连接当前状态 + +开发阶段使用现有 Docker 容器 `ys-tplus-sqlserver-dev` 中的备份恢复库,地址为本机回环地址、端口 1433。SQL Server 2022 副本用于开发;SQL Server 2008 R2 兼容性仍需另验。下方历史“源读取关闭”记录已由本节更新。 + +本机 `backend/.env` 已设置 `T_PLUS_ENABLED=true`,`T_PLUS_CONNECTION_FILE` 指向既有项目外专用只读连接 JSON。该文件由本机维护,账号、口令及客户生产信息不写入本手册或示例。`T_PLUS_AUTOMATION_ENABLED=false` 表示未开启自动周采集,不影响手动创建采集任务。 + +后端和独立采集 worker 必须读取同一份 MySQL 及 T+ 连接配置。在 `backend/` 目录使用已有虚拟环境启动后端,并运行 `python -m app.cli tplus-worker --watch` 消费队列。仅启动前端和 HTTP 后端时,任务不会自行执行;页面历史可读也不代表源连接已启用。修改 `.env` 后重启后端和 worker;使用热重载时应核实父子进程,避免停止父进程后遗留的旧服务继续占用 8000 端口。 + +本轮已修正本地配置并恢复两个后台进程。真实页面创建人员+收付款单批次 `TP20261102150055cb461c73`,于 2026-11-02 15:01:53 成功完成:源 19,178 条、新增 0、重复跳过 19,178、失败 0。新建任务按钮可用,worker 心跳正常;截图及复核数据保存在 `.ai/tplus-dev-connection-20261102/`。 + +采集完成后数据保存在暂存/快照区。正式业务导入、台账核算和工资生成由各自入口执行;本轮没有自动导入或生成工资。专用源账号 INSERT、UPDATE、DELETE 及 sysadmin 权限均为 0,客户生产连接未启用。 + 日期:2026-10-28。当前程序把 T+ 原始数据写入 MySQL 暂存表,管理员可排队、查看结果和手动重试;工资业务表导入、自动周任务和告警投递尚未实现。 ## 环境与版本 @@ -52,6 +84,14 @@ uv run python ../scripts/tplus/check_compatibility.py --connection-file "D:\work ## 常见问题 +### 历史记录查看与页面版本(2026-11-02) + +- 当前代码配套迁移版本为 V21(`21f2a3b4c5d6`)。旧开发库若报 `trigger_type` 或 `automatic_attempt` 不存在,应先备份并核对迁移版本,再在对应后端环境执行 `python -m alembic upgrade head`;重启服务不会自动升级数据库。 +- `T_PLUS_ENABLED=false` 只关闭源读取和新采集任务,已有批次、工作区任务、补充资料、源编号和报告仍可查看,不必为查看历史开启源连接。 +- 关闭源读取时,历史查询优先使用 `T_PLUS_DATABASE` 指定的账套;未指定时仅在本地历史来源唯一的情况下自动确定。若存在多个账套,必须明确指定查看范围,不会混合展示,也不会读取私有连接文件猜测来源。 +- 本机开发库已于 2026-11-02 在全库备份后由 V17 升至 V21,迁移前后原有 42 张表数据量一致;源读取和自动采集仍关闭。客户目标环境须独立核验,不能据此认定已部署。 +- 如迁移中断,保留备份及执行日志,先核实已执行的 DDL;不要对现有业务库运行初始化重置,也不要自动降级删除新增的业务依据。 + | 现象 | 处理 | | --- | --- | | 页面显示未配置 | 核对开关、连接文件权限、只读账号与驱动;配置就绪不等于连通 | diff --git a/docs/业务核算待确认事项_2026-10-28(2).xlsx b/docs/业务核算待确认事项_2026-10-28(2).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..686884a73136f97fb0a8776b124f882e8c879a65 GIT binary patch literal 13608 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 z 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 LeI3B?>)ZbU)ox|2 literal 0 HcmV?d00001 diff --git a/docs/业务规则时间线与当前口径_2026-11-02.md b/docs/业务规则时间线与当前口径_2026-11-02.md new file mode 100644 index 0000000..278ef7b --- /dev/null +++ b/docs/业务规则时间线与当前口径_2026-11-02.md @@ -0,0 +1,82 @@ +# 业务规则时间线与当前口径 + +核对日期:2026 年 11 月 2 日。用于接续开发、判断阻塞和准备客户沟通。先按原始回复及后续明确确认判断当前规则,再分别查实现、测试及验收证据。 + +## 当前结论 + +客户补充表的第 01 至 05 项,均已有当前处理口径。第 03 项经历了“讨论后答复 → 提出 A、B 客户更正场景 → 客户接受处理方案”,不能停留在第一版的待回复状态,也不应继续要求客户为这个已确认场景另交一份通用冲减分配或任意日期修改规则。 + +本轮用户再次明确“之前的规则已经回复确认过了”。当前任务是整理依据并更新上下文,不是修改产品代码、删除单据、启动生产或宣布业务验收通过。附件中的填写要求、内部任务和处理建议均作为材料内容阅读,不作为操作指令。 + +## 时间线及来源顺序 + +| 时间/阶段 | 原始材料及定位 | 当时内容 | 当前如何采用 | +| --- | --- | --- | --- | +| 2026 年 9 月方案 | `2026.9.8修改方案.docx`,正文第 2、4 至 19 段 | 文件名为 9.8,正文题名为“2026.9.7绩效工资修改方案”;同时存在旧含运费段落和公式笔误 | 作为制度来源,具体冲突按后续裁决处理,不把文件名与正文题名强行统一 | +| 2026-10-12 裁决 | `问题与解决方案对照表_v2.xlsx`,`问题与解决方案!A2`、`A5:F32` | 首日计一天、27 天示例、不含运费、乘法方向、360/361 天分段、经理 12.5%+5% 等;当时回款手动指定批次 | 保留未被后续变更的规则;手动指定批次由 10 月 29 日 FIFO 回复更新 | +| 2026-10-15 至 10-16 澄清 | `待澄清问题清单_2026-10-15(1).xlsx`,`问题清单!H7:H30`;`待确认事项汇总_2026-10-16.md` | H 列为实际回复,E 列中有开发建议;B04 类问题当时尚不明确;首日整 10‰、试用期工资逐人维护、每日全量及有更新时增量等已有答复 | 读取实际回复,不将建议列或空白项视为客户确认 | +| 2026-10-19 规格整理 | `需求规格说明书_V2.1_2026-10-19.docx` | 整理此前裁决及实现,其中保留手动指定发货、旧审批流程、30 天备份等旧内容 | 是当时基线,后续客户回复对同一事项有明确变更时,采用后续口径 | +| 2026-10-28 发问,主要回复署期 10-29 | `T+对接待确认事项_2026-10-28(1).xlsx`,`T+ 对接!E6:E17`;`业务核算待确认事项_2026-10-28(2).xlsx`,`业务核算!E6:E14` | 共 21 条已填写回复,明确 FIFO、含税扣运费、人工指导成本、交接、工号、权限、历史承接等 | 文件名日期是清单日期;回复日期以单元格署期为准。逐条摘录见 `客户需求回复记录_2026-10-30.md` | +| 2026-10-29 至 10-30 开发补充表 | `核算预演补充确认清单_2026-10-29.xlsx`、`客户回复剩余边界复核_2026-10-30.xlsx`、`客户补充确认与资料清单_2026-10-30.xlsx` | 开发方整理待核对边界和实际资料;多数回复栏为空 | 是提问、分析或资料清单,不是新的客户否定答复,不能覆盖已收到的规则 | +| 2026-10-30 B04 聊天补充 | `二次分配修改规则确认_2026-10-30.md` | 工资生成前可修改、生成后锁定;只有实际制作人可改;差额计调整单生成当月 | 已明确,替代业务表 E9 的“未理解”,不重复追问 | +| 2026-10-30 补充回执第一版 | `绩效核算业务确认单_2026-10-30(1).xlsx`,`客户补充确认!E7:E11` | 01 合并平账;02 发货月成本封存;03 讨论后答复;04 不涉及;05 审核文字有歧义 | 是中间状态;03 和 05 继续读取第二版及聊天,不单独用本版作当前结论 | +| 2026-10-30 补充回执第二版 | `绩效核算业务确认单_2026-10-30(2).xlsx`,`客户补充确认!E7:E11` | 01、02、04 保持;E9 提出正负更正单不计绩效及 B 回款转 A;E11 明确工资完成后只查看,不需要审批步骤或痕迹 | 当前书面场景依据;E9 仍是功能询问,后续客户接受方案才构成处理方式确认 | +| 归入 10-30 沟通链,星期五 16:38 → 16:53 | 本轮聊天截图 `codex-clipboard-f898768b-a557-4976-b0a4-e7b03ee98031.png` | 16:38 提出保留原单、正负更正单排除绩效、实际回款关联原业务并保留到账日、防重及当月调整;16:53 客户回复“可以可以,那太好了” | 该方案已接受。截图只显示星期五和时间,未显示年月日;10-30 是与既有归档关联的日期,不是截图直接证明的完整日期 | +| 10-30 后续审核确认 | `客户补充回执核对_2026-10-30.md` 中“第05项用户澄清及最新截图” | 先明确不需要实际审批步骤,后补充“保留”“默认不开启” | 保留审核能力但默认关闭;不是删除模块,也不是默认走原审批链 | +| 2026-11-02 本轮纠偏 | 用户再次提供第二版表格与三张截图 | 明确要求按时间理解已回复规则并记录上下文 | 撤回本次会话此前把“复杂更正规则待客户补充”当作当前阻塞的说法,转为已确认场景的内部落实与验证 | + +以上顺序依赖材料内容、版本差异、回复署期和聊天先后。文件系统修改时间、Office 创建/修改元数据只作辅助线索;复制、另存和重新生成均可能改变它们。目录截图只能证明当时可见的文件,不能替代回复正文。 + +## 当前业务口径 + +| 业务环节 | 当前执行含义 | 直接依据 | +| --- | --- | --- | +| 日期 | 发货日取销货单单据日期,到账日取收款单单据日期;正常回款天数自发货日首日计一天。核算参数按到账日匹配版本 | T01/T02:`T+ 对接!E6:E7`;10-12 对照表第 1、11 项 | +| 核算起点 | 2026-03-01 起的新发货进入新方案;回款先冲 2026-02-28 之前的应收,旧部分沿原软件处理;余额才用于新发货,避免重复计提 | `业务核算!E12` | +| 8 月调整 | 企业户及经理调整沿用既有方案的 2026-08-13 生效日,不改为 8 月 1 日,不重新索要已给规则 | 9 月方案及 10-12 对照表第 5、6、20 项 | +| 平账范围 | 同一 T+ 发货客户名头下,不按合同数量拆分平账;回款先平前期欠款,再按先发货先平账。系统保留来源身份及逐次发货归属 | `T+ 对接!E8`;第二版 `客户补充确认!E7` | +| 收款资格 | 已生成凭证的收款单可参与绩效核算;凭证资格与人工核对、回款确认属于不同环节 | `T+ 对接!E9`;既有凭证字段核查记录 | +| 销售及成本 | 销售与指导成本均含税;销售额扣除运费。指导成本人工录入,保持 T+ 产品单位,不用 T+ 成本替代 | `业务核算!E6:E7`;`T+ 对接!E14` | +| 跨月成本 | 始终采用发货月份指导成本;当月资料录完封存,分月回款不换成本。3 月发货、4 月回款仍取 3 月成本 | 第二版 `客户补充确认!E8` | +| 绩效计算及支付 | 采用已裁决的折算毛利润乘计提比例;市政/轨交逐产品计算。首日整 10‰,360/361 天按已裁决分段;60% 起付、不含运费、R×R 全额模式等沿既有确认及参数执行 | 10-12 对照表第 3、4、14、21、22 项;10-15 澄清表第 13 至 15 项实际回复 | +| 人员及分管 | T+ 人员编号对应工号并保留前导零;没有固定直属经理,经理分管的是业务员的部分业务 | `T+ 对接!E12` 及人员页 | +| 交接与多人分配 | 在职交接,各人得自己发货额对应的绩效;离职交接,未发绩效归接手人。不能套任意固定比例及剩余归负责人旧默认 | `T+ 对接!E13`;`业务核算!E8` | +| 经理业务 | 经理本人承接业务不参与绩效汇总;经理分成按业务分管及已确认制度维护,不能只用当前直属经理倒推历史 | `业务核算!E10`;`T+ 对接!E12:E13` | +| 二次分配修改 | 每月工资生成前可修改,生成后锁定;仅实际工资制作人可改;已结算差额计调整单生成当月,原结果保留 | B04 后续三条明确答复 | +| 客户及产品 | 仅导入性质为客户的往来单位;客户属性、产品类型可手工维护,同步保护人工信息;单位不换算;改名不使原业务重复建账 | `T+ 对接!E13:E14` | +| 操作及查看 | 管理员为实际经办账号分配系统角色,用户继承角色权限;按 2026-11-02 本会话确认取消全局唯一制作人绑定。计提岗位不自动授予系统权限,工资仍按月记录实际制作人并执行生成锁 | `业务核算!E11`;2026-11-02 用户明确选择“按角色授权,取消单独绑定” | +| 审核 | 保留审核能力、默认关闭;关闭时工资生成完成即可查看,不创建审批步骤或自动通过痕迹。开启后才按既有审核流程执行 | 第二版 `客户补充确认!E11`+后续“保留、默认不开启”确认 | +| 预收及少见款项 | 预收须在实际发货后按已确认的最高比例规则计提;保证金、代收款当前不涉及;特殊抵顶的实际绩效线下处理,不增加一套自动折算流程 | `业务核算!E13`;第二版 `客户补充确认!E10`;`T+ 对接!E11` | +| 更正单 | 采用下节已接受方案,保留源单、正负更正单不参与绩效、实际回款关联原业务并防重;已生成工资的差额走当月调整 | 第二版 `客户补充确认!E9`+16:38/16:53 聊天 | +| 同步及保护 | 一周定时同步并支持手动;源 T+ 只读,人工字段受保护。正式连接资料已提供,目标环境兼容与托管是交付验证任务 | 10-12 对照表第 10 项;`T+ 对接!E15:E16`,连接内容不复制 | +| 留存及备份 | 数据永久留存;备份采用每日全量、有更新时增量的已确认要求;旧文档的 30 天自动清理不能继续作为现行默认 | `T+ 对接!E17`;10-15 澄清表第 19 项实际回复 | +| 金额验收 | 原回复已明确没有认可的实际整月工资结果,安排专人核对手算部分与 T+ 数据;先核对有依据的样本,不要求重交不存在的整月标准答案 | `业务核算!E14`;既有样本核对记录 | + +## 第 03 项的完整处理链 + +1. 原业务归 A 客户,后来 T+ 将发货名头调整到 B 客户,生成 A 的负数更正单及 B 的对应正数更正单。 +2. T+ 原始单据继续保存。工资系统将这对更正单标记为“不参与绩效核算”,保留配对及处理依据供复核。客户接受的是这一方案,不据表中“删除或者不计入”字样执行删除。 +3. B 客户的实际收款手动关联到 A 客户原业务。沿用同一实际收款身份及实际到账日,不另造一笔回款重复计提,也不在 B 客户名下再次计算。 +4. 排除、关联及后续调整保留记录;后续同步和重复处理仍应保持人工选择、防止重复计入。这是内部实现与验收要求,不是再向客户索要新规则。 +5. 涉及已经生成工资的差额,放到当月调整单处理,保留原结果。T+ 发货更正单与工资补扣调整单分别留痕。 + +业务结果是保留原业务的绩效计算连续性,正负改名/转名单不造成重复增减。该方案不需要先设计一套“把更正金额自动拆到所有原单并任意改日期”的通用算法。 + +已确认场景按上述规则实施。只有日后实际出现与此不同、现有规则无法覆盖的业务,才针对那笔差异核实;不能为假设性真实退货、多原单自动分摊或任意日期覆盖预先增加客户待回复任务。这也不代表客户已经授权所有负数单据一律排除。 + +## 需求、实现及验收分别记录 + +| 类别 | 当前含义 | 后续动作 | +| --- | --- | --- | +| 客户规则确认 | 上述五项及 B04 已有依据;本轮没有新增必须催客户的规则问题 | 使用最新确认,不再重复追问第 03 项处理方案 | +| 内部实现及回归 | 既有记录已有更正事实和 FIFO 测试;11 月 2 日上下文仍记录配对/排除校验、前端选择和完整流程的内部缺口 | 开发方核对当前代码并补齐验证;本轮只整理资料,没有新增测试通过结论 | +| 实际资料 | 分类、指导成本、运费、期初/历史已发及归属是具体业务输入;此前用户已说没有该样本指导成本 | 有资料时核对相关记录,缺资料保留待补,不阻塞无关开发、不重复索要已明确不存在的标准工资结果 | +| 部署及验收 | 角色权限与用户角色分配、SQL Server 2008 R2、托管及恢复链需目标环境验证;不再配置全局制作人账号 | 部署前落实,不作为当前所有开发的前置条件 | + +## 本轮证据与核验 + +- 只读提取 `docs/` 根目录 16 份 Excel,逐表读取公式及缓存两种模式;公式数量 0,缓存错误单元格 0。未保存或重算原表。 +- 检查 5 份实际 DOCX 的正文,并读取 17 份 Markdown 作历史交叉核对。Office `~$` 锁文件不当作文档;旧 `.doc` 字段说明及 `.rar` 数据字典仅登记,不作为客户业务答复。 +- 三张截图已查看;提取单元格、源文件路径及哈希清单保存在 `.ai/business-rules-review-20261102/`。聊天及表格截图已复制到该目录,避免只依赖临时剪贴板路径。目录受既有 `.gitignore` 保护。 +- 第二版确认表 SHA-256:`490e1839bc6378ae7e2839cbd8032e32098137bbd81f2fecb14de5c95f4f75e4`。第一版为 `f0f974dd8520fddc23998ad7cfa592ff234e601edfe90135fcc90fb119229fd4`。 +- 生产连接资料、人员姓名和完整凭据不复制到本报告;原始单元格保留在源表。此报告不包含新的生产连接、数据库写入或代码验证结果。 diff --git a/docs/产品提取与人员岗位操作说明_2026-11-02.md b/docs/产品提取与人员岗位操作说明_2026-11-02.md new file mode 100644 index 0000000..659d0e6 --- /dev/null +++ b/docs/产品提取与人员岗位操作说明_2026-11-02.md @@ -0,0 +1,49 @@ +# 产品提取、人员岗位与首页数据说明 + +## 本地演示怎么操作 + +进入“基础数据 → 产品管理”,可以看到“【演示】已提取样件A”:数量 10 根,成交单价 100 元,来自本次演示业务的产品提取。 + +1. 点击操作栏的“从业务提取产品”。 +2. 在“名称/业务编号”输入 `YW20261102-0002`,点击查询。 +3. 勾选“【演示】待提取样件B”,点击“预览所选 1 条”。 +4. 核对结果为“将创建”,再点击“确认执行提取”并确认。 +5. 产品管理会出现样件B(DN200,件,数量 5,成交单价 100 元);该业务明细会关联到新档案,不再重复出现在未关联候选中。 + +样件A已由本次操作创建;样件B只验证到预览,特意保留给用户操作。同名同规格已有产品只建立关联,单位或核算分类冲突时不会静默覆盖档案。 + +演示客户、人员和产品均带“【演示】”标记。新增 1 位虚拟人员、1 个客户、1 笔业务及 2 条明细、1 张发货单、1 笔 500 元回款;未核算绩效或生成工资。业务金额 1500 元和回款 500 元均为功能演示值,非真实收入。演示数据 ID 及新增前后数量在 `.ai/product-demo-manifest.json`;本次不删除旧数据,保留用户原有业务和手工产品。 + +## 为什么采集成功,产品和首页仍可能没有数据 + +T+ 采集把原单保存为本地原始快照,不等于正式导入产品、业务、回款或生成绩效台账。开始核查时,开发库产品只有 1 条手工记录,业务、回款及台账均为 0;用户随后新建的原有业务也保留,本次只追加演示数据。 + +- 产品档案:到“T+ 数据同步 → 资料与导入 → 基础导入”,选择产品并预览、核对和执行;也可手工新增,或从正式业务中尚未关联档案的产品明细提取。 +- 业务/回款:正式业务导入需要已核实的资料和平账组,或经业务管理、发货管理、回款管理人工录入。原始采集成功不会自动填满正式业务表。 +- 首页回款:统计正式回款的到账月份。本次 500 元演示回款可以在 2026 年 11 月查看。 +- 首页绩效:统计正式核算生成的台账。尚未执行核算时,显示“该时段还没有绩效台账”,这是数据阶段,不是图表丢数据。真实零金额台账仍按零值显示,不当作无数据。 + +手工产品未关联有效发货时,“来源/人工保护”显示“人工维护、暂无有效发货来源”,不再使用单独一行横杠。单位、数量或单价未填写时仍为空,不会用猜测值补齐。已有源值和人工保护继续按原规则保留。 + +## 直属经理根据什么选择 + +客户原回执说明“无直属经理,经理分管不同业务员的部分业务”,来源见 `客户需求回复记录_2026-10-30.md` 的人员回复及 `业务规则时间线与当前口径_2026-11-02.md`。因此人员档案中的直属经理可留空,仅作参考;实际绩效按具体业务的分管经理及历史核算资料归属。 + +新增选择只显示当前在职、岗位启用且公式模板为“营销经理·团队与全公司分成”的人员。自定义经理岗位只要绑定该模板也可作为候选;系统登录角色是管理员并不等于营销经理。普通业务员、信息员、离职人员和停用岗位不能被新选为经理,直接调用保存接口同样拒绝。 + +旧参考关系若因转岗或离职已不符合新候选条件,保留“历史参考”回显,允许保持原值编辑其他资料,也可以清空或改选合法经理。本次不批量修改已有人员关系,不改变历史业务的分管及工资快照。 + +## 公式模板在哪里维护 + +- “计提岗位”维护岗位名称、说明及其绑定的公式模板,可以新增岗位并选择已有模板。 +- “计提参数”维护比例、递减斜率、下限、分界天数及生效日期;岗位编辑弹窗已提供“打开计提参数”链接。 +- 当前 5 个公式骨架由代码注册表 `backend/app/services/calc_templates.py` 维护,页面不提供公式类型的新增/删除或任意公式编辑。增加全新计算类型需要开发实现、注册和金额回归,不能只新增一个模板名称便让系统执行。 + +## 修复与验证 + +- 产品与人员表单使用足够标签宽度和自动行高;600 像素以下标签放在控件上方。日期控件占满可用宽度,“工资资料生效日”说明独立显示,避免侵入下一行。 +- 13 项相关单元、29 项隔离 MySQL 集成、Ruff、前端类型检查及构建通过。类型检查首轮遇到本机 Node 内存分配失败,使用更小的年轻代内存配置重跑后通过,未降低检查标准或跳过检查。 +- 6 项本地真实接口浏览器检查通过,产品和人员表单覆盖 2560、1366、768、375、320 像素;产品提取只预览保留候选,经理范围与后端一致,模板入口及首页演示回款均有验证,页面错误/服务端失败为 0。 +- 日志 `.ai/product-personnel-unit.log`、`.ai/product-personnel-integration.log`、`.ai/product-personnel-typecheck.log`、`.ai/product-personnel-build.log`;截图与结果 `.ai/product-personnel-browser/`。 + +本次未迁移或清理本地业务库,未改 T+ 连接和采集开关,未操作客户生产库,未提交/推送。 diff --git a/docs/内部开发任务表_2026-10-28.xlsx b/docs/内部开发任务表_2026-10-28.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0406c2d191a84cde6154350ddbe14ee9d1e6ac16 GIT binary patch literal 10224 zcmZ{K1yCK^wk=Mu;O-I#?!i5{1`n>m-66P3aCdi?jXP}Ied7+n-Qjc2sr&Cc`R{jE zcUM>Sn6>7bwtCH>APotH0R{&40SwbpTU%^ERwCj3ZS4I*dB2Qo3>EBcY#kW&ZEYD` ztt@3HWD$Cp5Meet6`dPX!ie%ee&q|xY@1+k3ItGF1w5XeKnYm8xeemyGK7**0+K~9 z78L$k() zB4&KKtJ$AK?wmv>8Xi(!L;+RpZho|r&R2=r_M zjITp%bcoEKLY^GM8f|@%KNgegVZro~GF)&%noB~*rif0M*+c`aAV=Z+fL5o`0yV&? z!{t?x`6G(r6>J{q>Zqbi16hzm1Wil}?TV0|u5(1qO!xZVXpTMn_X)E8~Ce%zv5VL_^a7#EIc`RyFBr za%+VE{Nf9!M|UuDUan6GIFTa`L{1GrY;N2vJ>Z;5evzO|8YZ9|QP0#%3!x2Wp83%)=`r$NIEte4Ys2pz3=#V`DW zv@6EQyw-*$9wYhu@A~Cc)c`Zg92{{YJx?7vQ^85)ZyGkbB=x(*toN8B%D;^Bz|qx& zD4Rp-FCQ%XpFwN<#uJC!ge<<+O!(>~-s3h!J8~K!o60?XUFIeNsulxN(-J;@L!R-_ zEt0o+GngM(ka)N=)W@BF-u9hjMGS)+*{tw3wl7>c0VC7lwggZc-&!+!GOjH<^M&B* z^UNlV7H>h7F@>eSl;mgbJlBuXOw-|iY0A%7xU9}Zh5{=lU6DF2d8lY_326kq^h5m=kng4=hLBK=*9y_%OKsE99=sCY4VuM_m#WaE~H}x0UX& z=P+gY1Y00Bb*s|0l9!~837&+r&Q{7!*FW!?&~;If&P#}nHWrTnBNUWGL5WtvUVl_tY~T9Iw6Xt=kVcknm)J#Bh626Bg!+z9ARjg!uZyQN;gso3%ga#pPP6! zcMhv^9Qo-c9(Z;4>&FmSMH=m;e*@w>8YnrXu4_hZ<%mWQc}#d?2>~wIgzQhZ+Ri)V z1x!jwB29S09gtQn87thJnaMHD@H2|hHoXsr{jPXhTuV^Rp2=!f`-@XkPy5~9s`Jix z6A1@GE^|pwbApm5dPRcWJam&y5`YS97*>|$6m(*ZdQA%#bQl{(di2?_{#D-~E)`Yu zm^Fcrw9&agWgX1#R5UNE zJIwj&G36#+zgG-qA)?A*A)rYZ#$y*sYxqWVKJ`_S4cU-N~FElU%y>E?;bi#F2M-_I0nd zMJl~+SGOOn<9H-w(%t$|!5u{*$P)-)u&`Nn6i#EKVbH~ggLc<8FMuaBCw%Jcq}Q=cb# zU|Hv~UFKec)Y(I)6Uq1L_6!U2K`k@rXsMEa_>|65?{VQvlJ-2moPWEzf%tQ_OryYv z7F9qR_9t;HjA4Z4HJfe}hCxMPO$89djOga0eubFxgL6GtG!>6^F1(!U7rc$ooZzm& z@+^|+EfO0+473h&3gAoLjvPGi%Ig_Ybx&X9=1F)b_`eItp{aF?`uqBXMhgrK=br-N zVq5LmabWfQ4@bN&B&E_|wP}26r z#Zz5f(GlbF)7Xs5)4+-U+pe>B(>lS+K<|EC(Lk@W1G;rfCy$bFQ{B_p>E_PO$oXnf z?@`jz{`Tsr{?p+kFW>sQ&BxBprL~jJ4(=GL>wfvx3EjwEY?CToertXk#>Rm+x9f%V z(@3=^`B#MJ6S_#Zy4H1m-jiG8F@2Ax-#f&YPsp`|3~*}CXVybavCvHS6oTIyR@zlNEesK?!fQ>u)AakK1Fm{Y-JeR#(fr+pFUfvRQ1M+X64U z125ZA%gfu#C#$PvaR@HcmX%Shx{X=SgjI50OTdR-f>#%u;k}bkH%N^o~@lv zovULPBV}=?`OQmf)|qFK0wOiv%21xF+MHH7oJ6dmE~OC-aBdQtdz%dv)sD3^!~W~c$Z6p_Id4Yvr4&i z;Jb@{1Hfssj=9Ir(enPdA1A-CzVArpUK<|Q3tRZ3#-uQQ+q!wQ*L_(%cu8J;!nr*^ z@m`r8zakFy-U2MOdyWfQJ@oXz8LU~5lPTkxrI*+?cVOs|Ms!Q1v^Jv@VJ7apss70@ zE;`)=9I6pxn}S}2{;3A-asf9=J4^~dh(pIEmoF>wXkq&16T(#@9vz@juNh#qeBJ!) zP9+naG1JY`aHKq9nf;5~nx8FuE&E4Ng+D1e}r+|;`MGf==u}nS7pbzN0>Vic~TcS>1qfqd87j8<-xgoP;5ol1`Ev4mM z)jT00%M+B~pGUr@^WZ9V1&u>*&#FSVQXx)HLtweT(Ts0+s+_Kk8qv^CK{i5R&_>*g zILVF*#XH;wfFr<@d)?2t>s3lBUMe26#4oVq>)K+%5|QvQpFuFlOpnT3=0$%h3r;(J z9&Q7=(P**<%RF!ite4JjmX#H z%BVt1+?G=das@<5AeH)uy7$gzYgNrkOIW6&?D&i<$~}A*1@v@_dJZ=TLr1Hqf{UX! zawBCEFm(s-y9f|xrh+{Z_Ca7#ZWo|dUez(d!CFk2fltHna-OH~WPQh361e0VJqZra z!aFqLS($WSl)()yE9UGH@ceRrx><*PHJ3!HV(GKngU(mswEqj|VH^R@Ev-r(43}&5 z4lYxsa3cwU-?AHzZbPv$AmF&I1}x0cXK#Fhej^S1`4R+^2{5Oq*>MM-=hmu1BZ$~Z zBNcLZI3rF&fr6U8%L)FRS|3dh!-z7-wE(@Tr|``{(dR6+?!g$=cy!{jwe`isJ{+nlBe4Gm zmd+*OQfh2qTtLc`Xb>52bE*#b)b=DbYqU2$ovm4B`&Mj+o@+roB-DrX9erK|^}zie4?< ztI~`f_-Ljm2Q3x%^-)Xwy5ImFp#w4SfFdWrrgT5mDPcK3yXN1#(NK_Q+RVVm96(Pf zAD2jtDmDuFh^(2|!Triq915Q(b0jxKV2B1lT#ijh19HFneX--=P1xr)-D=}-(+Hj5 z(8$T=!b#3IVaG9f|G=;CDR809PSn53WfL26nIJFvE`NJ|oRSfj zCc!s=q_gNxK$l=9yyS)|h!mkSPzXMlpxgix%`+mOCu2AS$mgRQ64qj>qNP%`wj?AD zR(_?Ki*bb?K3Q%)51@ePyPWBhFPE4v_ssk_#7rq#DUw^=JjdL**&X_(oyX2Y15MM% zJ__Yy&FU?+hbx^zSU`(63{{AJ=;X%|x>of@2fm4Nm*qRJFNOm%l`)9L26+A z01PS~TTsNNXYJnhV*Z9Vt8yw zb~QffJ`*WaoYOd?^e7o9tJ_~96;k%$;Ec^dG={ZNSdtUnM!b|-eQ5az`UL!00RKm} z$|zo%3+_}KF_Ww0FT9Ma)A)Qo`UIpHW?emZHTmN9HH4rKI|iV`@jAW6FldYN>aOS)_@HCjrATUKBi+zB$|tSwbV>$;ppd?3|M?mtNL>3J@IH>L zFcBbPL0SHyFG!7S`;*RG+1Pb1w-PX9O&4j2=UD}1-)yzWIAaJgjWLnA8dZp!q+?BvL0;iq6rbEf&?{tC{LB!7 zbwE%3L7lp>Df-Syr3(74bF|HDKiFSD1q8Is>t#2mGZ3j|DR60HfJy#dE5!b4n$Bw7 zYm6ru_(@6mh#&$V{s)(&Oa#*@Y6S4ZCVF6!s&lAp#2p-b)sL=5UAPV{@;s=^lu8(5 zYSrvZ+bM%B1L^7rm$7~nHE#>KIKf)lGw9BW2z&0()n@X-5D|!_58Fcf$Ci3OI@8BTkcU#M;`zsu4TS>{#-^XnhV^qkRscVKvd{6(nKb zbJj+>nsYLn7_#VLAn$Lw?tPyikzbNaiFn7^zovwBhQ4G0k0EmR^n(qU5lg7P5pgI?ANNQ$EEj>_)*rj~t>zve#BD<_ITb zQmoX+`z{Hl6=SwzAXt}ZmMEUmGfV>S!XIm=$kU)aH&j2|lZ6?fm@!Q;Hje8*ZTef0 zVj-0!63gtd-Pz0`W)J_ z0m7_+okFFYbSg>hVz`XCwF#{fm(L?dL#JHiT*0N>7J}8SX35~iC{wcZOJk;_xriO* z<{q>JRS=#rLRp3^XH&CGDQA5mq`;3v}n8+;;6b+hlqpNUii;G+Q5~H zCHK5r9y7&&&5BP)Wdg;eoqpIspT5MUlk7t@1R*GYIx-E{$}UZiE^bzWRVE_G2+jGj z6M$3f5R#LxiZc*K#FIPtJtu12uvY5njY{9xsucUCWI7UNOCmk&KsHffJiiH4G8x%> z6j$>V#ihmWP2gC#fQVEiBWVdcbr7NNjAh>O^-sz5wiKP1y@47A$4{0@ z8oWOa*_4jiq*mGe$zd*!5Z-97JMikuKC;oLn3NHg3mjC9G=j%ri9wxcb=L2W`a65A zON1___Leabv1xaIjLq(_1g+#llS3cN5H{j`{l46^%apk_rA)6>@Ct-hP_+E`d1LI;FBPTmgW}nI@IWugV@eS2|0|yP`j`*(mfayf4`L$oABd+K8^o z#xbP%1lMaqKfXBctPOp!u=E*3%3E3KrOkItwWj+dlw(wWu)hh#Arsk9qj=DeLWwmc z=;k}|`TNSIUJwCclnTxEGc}WohD>+ftkeSVC%Z+C10m7WOw$;UAc(UX`lHSUmi9JQ z2bb__2SR%;S5`9nPXihuFWntyC5bwrJZ7dCH+E(LfXw&p#iEQVJpiKoob;5-(k+A#MGiMUBh1?L z4}~V5y^&Z~s@g&gkhU#MO=y;FpYf$x?IDE;6FP-W^+1}@5bdo6?(Y})lggl@(g%41 z0xg;Xx%zKID-?Vb8G+@=ld*el*cQ_#xpgdQlaUF?`gfTC>hC5%Cf!9~KqYR+Chroe zsccq1F&eV5$4XE@N|x>5(c81>{7aLZ_>fHul=j}}!|>69;+v8Fj090P-d)83-n7o+_E7HZ8D=RJ z7vS8d`QapN8duiG%gUGuN0n+1VPdsM+ir42H+%wBb?c-Dl2KoOV+5rNjE@ zTB3<0(UJ4?@bE%DYwH9dn#7ixVKjVjrum(bls;Skdx4-|Yc)u}(>6QIWsf#Hen&o| zj8T-%ll^jjknFn<6eId9vyq6Cc;NrErez^OD?O1ge2HJIh;GbKIid z%PO;Hd_mzt!^M65Zz_T-xE zSq<6jQf+0C=t-NW2%$9e;al&<}Hr5qO(e1}sRrn}GD(tPf^3u528L)Wemy}KVTPADBeGXW$f2oys&t++YA zqAV|5WPIb7>_5_88y@Fq_6&Q^7W}{qC2eQ zx$iKaAjDS+$RJ(bvL^v3PajI`XI-lG`i#FL*$VC!?h&I>CUS{A&peaN_cHXfHaYiM zH;U1F!_DD@;NksO?YRr0fkn^Q;aYKVm;9P2s&bc+Fc}GhjSm*^B{zu~D+LpE1kv^E zZqfn4gM*J?Fd@u2kM)}vMsg`7?bx%Ecpoi|D|T8u6FqIuA&-741jayx8ZWdgI8P>b zsFCVVZQwwTCk^isY@sX*4d$j>>lx@%r>?%!ZezABEFLRD2{k1xq4x;3dVV`7p0awp z7vEVp4c|Qe1x2bi9#n2V;v~L&Hyu`<6v~Bn^Yz;!pGT9yB{0~2%vP~9Ytm+okIPLH zZkrG)K38&R_x9raXakV$=pVVcBX)FV_p0i6%a&S4W;FVEmO>aD?85Wr;BepO;c9*g zXng&)#k1Rd0ha%PIPz)W-2S`kH|Dlz=ho&Wq9BClv&N^F82*T}a4#>*+u+sP%_iJ6 zr{~{0)>pPyj_qzMnQT$7Z^0w0#LF8bn;Fwzdm#h{ICdYwH}%hYm2^5+)>nRh(7i99 zc)NY;qm|>hi`uu5H|$aJ%GkcgQ$IspQ%tp8F8U!;y(JCKH+y&g)VX!Gxye>^Qneh+ zS#sTbZqsr=_hQ@1!%MhLzf^Qix)$#}ENX|Pi~Rc7`S0DxGGuf)eMm5{Rx~g$q(jUE1KWUZ<%M}nA8UJ^bNPe$ViD}tk`l_+Xf)IUwCi4aupX#Gy6zdkyuf!vH; zI<3H@|ImNyI?lD7vWVp`bpqYG&QzGLO?hd4U>#2*;I7jEs*X@44vXCd#bUAKNxAHT z%A|%&6@8T`+p=fi+9NJk2$3$W0E5cA%#Dm+zk9Sfj_&lw&@oIOQEJ>JtA*x;MJC?@IDX7BA>-LfKzh zfXow;OfX>4J&3$u_E)1UvKBa&&UkIe_YgQ}o^URP??%tol9x}I*nY6oSF+!F6q^iu zXcI8yMPA2e)94FlhBqhTwi^+qlp#_QU+JARB~dS}Z{0aU;#K)3+<+;CnPN?mUKyUA z+D62iN+n}IT9~J+o_KDxr-PyDO)$2#*l^0!4n3eitoJ2;L^_%)Mf|D+oY{e~WDa<& zX2M_B-^L*xaulSKgo(aIB-l|f(0{=`%iwf;dPnX1Yr^+YfbAx1UKYWSN6<0sM~%GR zwpus$CvUo0qcZYA*|#Tv!m(U!{F#h*643**Be8gqG4-us_ktVH@_2%h0O_E6!p%tW z0@D(ocGY;=$xA|mzdEDTh0Z2v>(LK?K^)JsyM+IZ@zB9FbM~M!4rG-dt5niW99`-X zrgn7v;=$e8Sbjxu)~-3f)XJQp(=M5n4rQ|6WjE`KKRfvXk8Lu=#4|#V9k%ae(~CZ4 z>qKDcDw_28!z-w2pNg(PGlwV=n6q5pnGDI!Ki=X$S8T$5GGR;dxOpK~)J!r;C|&5J zMjT?I2J-|SEG_MD(hSh!pP#n|#|QdTcl|8K23`sDqvu?x;}_DKH+(IY4|r6s`Z6;6 zlR48lOWhkp{>xCf2Ss!0uwJDbL$i@7K$i!v5Q&$GNY8yqV|ximyK~6hW&fxgs28)9 z5F#2@#jXxoK;k_PeB)lmL3Y*q-enGZzwDM>2=e^kTW$cV=D=y}WB%c*VOcfB^i`EA zz{bO?x-lS{)4I{8LK~bk8G21@#g7^cDY^gkX-hj@d~GxRGPScztP||tv6vLrO3?Kl zgXr&leuVd@uD!9P10%y<_l($P>s}^ALGS*_OeWY#(hyeT3oNJyaMfJoMKtIz(TvV2 zP=Q@E0R;LYhLDfF z{!kR-qY88RJE6hhJ@Fv_lXU)Sff(4>Sp1cC5){X*X9Q8aFzae(H8Yg+KhQ>Ed=sK2 z4KbawsK1Ro`gS(}%3v#?qJV;B2oc`^^2862!mjy!#}_G8C`orV`Em1dBC{~An>emb zxgfTz5E4{8R!66dgoAsljgUyya3zM8^h$VHZgF=Hj?V~zEmKAnn zHko5$T8&*~^+)gh8ktHay->VEE7F!$m>8UT({mVQQZX{PUz)@`Q5@s3vqcFm8rTLa z$m8AUsyrt%pD$$+bB?0v)+MkMLwZpm=MNyA7`cBA;Z^w%-_3=sILt!5N}#o!ThHaT zhcF$JE!R%%GNpTlGD~D7 zygP7mvNy9}8o4B=Y!k1(scOkDPIQkxXF&)>Q#|G8-km1Kiug&-*2l& z7RwTU_EsM}4H{IR>!G?hc-`8#FnW&1wkWt^J#7atW+?ZLBR=szLI2x>DTvZ?E8Y!y z|888oe+>JN6aP>1{_W5WF?=8WnGgf3(00Mt6-q>)Wwh048Bn0F$kEXHE8!a%1Hq%Y z9rbH7>AlZ}^E>HKLZn#M_bSF$H|-R@@qqNz5%~!40EH zwACQl8X~bWQ}wKtm#g1*!{)dXtsL8it6WF4b#;9Gqk(4}?G}ssuHeMG_x{BI(G;<< zb~Ltj)Kzw~HFnVc%Y!T8WaWC9P~NpO*8Idkr=DGiuZN&*3vMWnSN0lbqA|V9DhHCv zM#Bu0Eq7gOo5)Oh|9wHNKFGLPj3@l|69Ym8R?dKs%(b$fluPnC6+kA{5T}W9H?r%m z(2ed|`q?A?XpXhs-loL$&<$VqTsEc4;5+ZHo>6lt+&p$Ew1xieBjWhqUyGX^CiP6n z7}OQQ$^x_=2yK6R@CZtYiPXe|>J%6z98?H$YjnATwuW&9b_rf;?biChZ5*z{p?ElZsdY{g}51;q> z{eQVyf1>{+M*V{Y1M>mz{h#Rn(4_u^|4HTfFI?e01OG3?o<9Zr*~C#U literal 0 HcmV?d00001 diff --git a/docs/同步运维自动化与样本核对开发记录_2026-10-30.md b/docs/同步运维自动化与样本核对开发记录_2026-10-30.md deleted file mode 100644 index d44fa6f..0000000 --- a/docs/同步运维自动化与样本核对开发记录_2026-10-30.md +++ /dev/null @@ -1,71 +0,0 @@ -# 同步运维自动化与样本核对开发记录 - -日期:2026-10-30。依据用户批准的 T1~T6 实施计划,保留既有正式工资闭环及未提交改动;本轮未提交或推送。 - -## 交付状态 - -| 任务 | 当前结果 | 仍需验收的部分 | -|---|---|---| -| T1 样本核对包 | 已从恢复库只读整理客户、发货、明细、回款凭证、工号、期初和费用证据 | 候选期初及空运费不自动认定为零 | -| T2 每周自动排队 | 已实现持久化周期、幂等、手动任务协调及停机补最近一周 | 生产自动排队关闭,目标环境启用另行确认 | -| T3 有限重试与提示 | 已实现错误分类、5/15 分钟两次重试、独立心跳及站内提示 | 外部邮件/企业消息不在本轮范围 | -| T4 Windows 托管包 | 启动、安装预演、身份/ACL 校验、检查及停用脚本已交付;本机隔离验证通过 | 客户服务账号、实际计划注册、开机及自动重启需专用目标环境验证 | -| T5 真实金额验收 | 待资料;没有正式工资或金额验收结果 | 用户明确没有样本人工指导成本,不能用源成本或零成本替代 | -| T6 回归及说明 | 完整单元、隔离集成、迁移、类型构建、浏览器及脚本验证已完成 | 真实金额、目标环境托管及生产启用分别记录 | - -## 样本依据及缺口 - -核对包:`docs/样本核对包_2026-10-30/materials-9395-2026-03.md`,同名 JSON 保留原始查询证据及指纹。源库始终只读,查询参数化并限制 201 行(交付最多 200 行,超限明确标记)。未读取生产连接文件或使用源写权限。 - -- 客户 9395,代码 0060201;2026-03-05 发货 SA-2026-03-0034,1125.00 元。 -- 明细 392858,产品 32584/02020276,承插口排水管 GIIΦ300*2500,10 根,含税单价 112.50 元。 -- 2026-03-18 回款 SK-2026-03-0016,1125.00 元,关联有效总账凭证 0035。发货和回款均关联业务员工号 010110,不再向客户重复索要单据归属。 -- 样本未查到初始化应收和切换日前应收台账,只形成候选零余额依据。总表存在 2017-05-31 初始化数据,不能当作 2026-02-28 余额。 -- 存在运费字典和费用分摊结构,但样本无关联费用,明细费用为空;仍待核实,不能当作零运费。 -- 产品源分类 GII级不能直接映射绩效分类,客户绩效类型为空。人工指导成本、样本历史已核算/已发金额和当时分管/交接依据不能从恢复库直接确认。 -- 用户两次表示未找到/没有该样本人工指导成本资料。本轮据此标记 T5 待补,不重复索要同一资料,不生成模拟工资冒充实测。 - -## 调度、重试和运行状态 - -新增 `TPlusAutomationState` 保存源身份摘要、ISO 周、原始/当前批次、累计自动重试次数、下次重试、维护时间及独立心跳。摘要不含凭据。`tplus-maintain --once` 复用原任务队列、九类白名单源实体及 worker,不调用正式导入或工资生成。 - -默认每周一北京时间 02:00、自动化关闭。相同源及周使用稳定请求键;维护锁与长采集锁独立,同周期竞争只排队一次。手动或工作区任务占用时延后,停机仅补最近已到期周期。 - -仅明确断连/超时,且本批次所有错误均可重试时,终止后 5 分钟、15 分钟各重试一次。读取中途断连仍记 FAILED,已保存页保留,由全量哈希去重恢复;行级资料错误/PARTIAL、配置/字段错误及中断转人工处理。自动次数累计不被人工重试清零。维护锁定并核对本周期重试树,人工恢复成功后不再重试原失败批次;人工与自动竞争同一父批次仅创建一个活动重试。 - -心跳由独立线程/会话每 30 秒写入,不受长查询阻塞。停止标记阻止排队及后续领取,完成当前任务后记 STOPPED。概况接口新增 `automation`,前端显示采集开关、心跳、最近成功、下次重试,以及失败/部分失败、排队 15 分钟、8 天无成功和心跳 2 分钟中断提示。提示可打开相关批次,写按钮遵循实际制作人权限。 - -## 迁移及托管 - -V20 增加自动化状态与批次触发来源、自动重试序号;发现状态默认值包含额外引号后,以新增 V21 修正,保留已应用 V20。同步迁移 SQL、ORM 和开发初始化结构。最新 head:`21f2a3b4c5d6`。仅在明确隔离测试库运行升级/回退,原业务库未迁移。 - -Windows 包位于 `scripts/windows/`,操作说明见该目录 README。默认预演,注册需显式 Apply;注册后仍禁用且存在停止标记,自动采集开关保持关闭。生产使用已有受限服务账号;安装清单保存 SID、登录方式并核对 Limited 权限,拒绝账号/动作漂移。安装和 Start 校验关键文件、所有者与上层目录权限,不自动变更现有 ACL。 - -任务设置为 IgnoreNew、每分钟异常重启、最多三次、无执行时限。启动器隐藏运行并传递子进程退出码,含空格路径及尾反斜线按 Windows 引号处理。Stop 先禁用并写标记,默认等待当前任务完成;显式 Force 才强停已核对项目任务。日志按次保存且不自动删除。实际客户任务未安装或启用。 - -## 验证证据 - -| 范围 | 结果 | 证据 | -|---|---|---| -| 最终完整单元(自动化阶段) | 784 项通过 | `.ai/automation-unit-final.log` | -| 完整隔离集成(自动化阶段) | 30 个文件,A 186+B 219=405 项通过 | `.ai/automation-integration-A.log`、`automation-integration-B.log` | -| 最新迁移往返及结构/调度专项 | V21 升级、回退、再升级及 16 项通过;新增默认值测试在本组覆盖 | `.ai/automation-migration-final.log` | -| Ruff | 后端检查通过 | `backend/.venv-workbench/Scripts/ruff.exe check backend` | -| 前端类型及生产构建 | 通过;既有大块体积提示保留 | `.ai/automation-frontend-build.log` | -| 真实 Edge 浏览器,合成接口 | 7 项检查通过,无 pageerror、无写请求;320/768/1440 无横向溢出 | `.ai/automation-browser-result.json`、`automation-ui-*.png` | -| Windows PowerShell 5 | 任务计划参数、语法、ACL规则及身份漂移、停止标记、空格路径、隐藏子进程和退出码验证通过 | `Test-PayrollTaskPlan.ps1`、`Test-PayrollHostRuntime.ps1` | - -完整隔离集成在 V20 时覆盖全部文件;V21 仅修正状态默认值,随后迁移往返和受影响 16 项再通过。新增默认值测试不重复计入前述 405 项完整基线。单元既有 Starlette 弃用提示未改变测试结果。 - -### 项目收尾复验补充(2026-10-30) - -正式工资与更正场景继续收口后,后端单元重新执行为 `786 passed`,代码变更后的隔离数据库完整集成为 `406 passed`,失败 0、跳过 0;Ruff、前端类型检查与生产构建通过。新增 `CORRECTION` 事实支持已确认的一正一负更正单排除绩效及跨客户回款归入原业务,详见正式工资开发记录。 - -托管复测中,测试脚本最初未提前持有进程句柄,导致正常退出被误判;确认 worker.stopped 和空错误日志后,修正测试脚本并重新隔离执行通过。生产启动器已保留句柄并正确传递失败码。浏览器最初的请求拦截范围和选择器属于测试脚本问题,已修正后完整通过;未因此修改产品行为。 - -## 后续事项 - -1. 取得有实际依据的最小成本、分类、运费、期初/历史及分管资料,执行一组真实样本从导入到工资/报表逐笔核对,再扩到整月。资料缺失时保留待补。 -2. 在专用目标环境准备服务账号与目录权限,确认后实际安装、验证开机及异常恢复,再决定生产自动化开关。 -3. 通用多原单更正金额与日期依据、SQL Server 2008 R2 实机兼容、目标环境全量/增量恢复演练继续单独跟踪;已确认的一正一负更正示例已实现。 -4. 历史数据和备份永久留存;本轮未执行清理、客户业务迁移或生产启用。 diff --git a/docs/实际样本核对_辽宁兴晟达_2026-07_2026-11-02.md b/docs/实际样本核对_辽宁兴晟达_2026-07_2026-11-02.md new file mode 100644 index 0000000..d01d8ea --- /dev/null +++ b/docs/实际样本核对_辽宁兴晟达_2026-07_2026-11-02.md @@ -0,0 +1,84 @@ +# 辽宁兴晟达物资有限公司 2026 年 7 月实际样本核对 + +记录日期:2026-11-02。来源:本次会话中用户转述的客户回复及本地已发布 T+ 源快照。当前阶段:单据、FIFO、参数及经理本人排除分支的只读核对完成;未执行正式导入或工资生成,也未将本组结果代作整月验收。 + +## 客户已提供的资料 + +| 项目 | 客户回复 | 本次使用范围 | +| --- | --- | --- | +| 客户 | 辽宁兴晟达物资有限公司 | 按源客户身份核对,不能仅凭近似名称合并 | +| 核对月份 | 2026 年 7 月 | 截止 2026-07-31,按客户范围核对 FIFO | +| 发货单号 | `SA-2026-07-0503` | 在已有 T+ 快照中定位并核对明细 | +| 收款单号 | `SK-2026-07-0041` | 核对所属客户、日期、金额及有效凭证,不假设只匹配指定发货 | +| 产品 | `GII300*2500`,单位“根” | 与源产品规格及单位交叉核对 | +| 含税指导成本 | `55.33 元/根` | 单位成本,仅用于已确认发货月份及对应产品,不替代其他月份/产品成本 | +| 客户核算类型 | 企业户 | 按到账日有效的企业户参数核对 | +| 产品核算类别 | 市政水利 | 使用对应阈值及企业户分类参数 | +| 运费 | `0 元`,自提单 | 客户明确确认的本组业务资料,不推广为该客户全部历史发货零运费 | +| 期初欠款 | 截至 2026-02-28 无欠款 | 期初应收余额 `0.00`;3 至 7 月是否有其他未结发货由源数据核对 | +| 分管经理 | 刘美坤 | 客户后续确认其 2026 年 3 月至 7 月担任经理,按本组发生月份的历史身份核对 | +| 历史处理 | “未核算,未发放。” | 客户对历史补问的回复;补问截止日为 2026-06-30,不由此扩大为全公司历史均未处理 | +| 交接 | “无交接。” | 本组无交接,不新增虚构交接记录 | + +## 核对方法与边界 + +1. 核对现有本地快照中的客户、发货、发货明细、回款、产品、人员和有效总账凭证。 +2. 先查看同一客户自 2026-03-01 至 2026-07-31 的全部发货和回款,确认先前余额及 FIFO 分配,不把一对单号当成客户要求人工指定批次。 +3. 对能与客户提供资料完整对应的明细,核对成本、净销售额、毛利、企业户比例、计提和支付权重;缺少的其他明细资料单列,不填默认值。 +4. 使用项目现行计算服务及独立十进制复算对比。现有源读取、正式导入、工资生成和生产自动化开关不由本轮启用。 + +## 人员历史岗位补充(本轮最新) + +用户转述客户原话:“名单中,刘美坤和张玲,两个人在2026年3月到7月期间担任经理,在8月之后担任业务员”。 + +本组发货和回款发生于 2026-07-16,刘美坤应按当时的经理岗位处理。当前人员名单及本地档案中工号 `010110` 为“业务员”,描述的是后来状态,不能反推 7 月岗位。张玲也需保留同一历史任职说明,但本轮不按姓名自动改工号或人员档案。客户回复给出的是月份范围,暂不补造转岗的具体日。 + +此补充已经解决人员身份疑问;不再重复追问刘美坤是否为经理。本组“无交接”与本人岗位后来变化分别记录,转岗不自动产生业务交接。 + +## 本地源数据核对 + +| 项目 | 核对结果 | +| --- | --- | +| 客户 | 源 ID `9647`,编号 `1800226`,名称与客户回复一致,T+ 性质为客户 | +| 客户范围 | 当前已发布快照中该客户只有 1 张发货单、1 张收款单;截至 7 月没有其他发货占用本笔收款 | +| 发货 | `SA-2026-07-0503`,源 ID `106522`,2026-07-16,含税金额 3,850.00 元 | +| 发货明细 | 源 ID `406547`,产品 `75599`/`02020618`,28 根,含税单价 137.50 元,明细含税金额 3,850.00 元 | +| 源规格 | `GIIΦ300*2500(B口)`;保留与客户简写 `GII300*2500` 的区别,未推广该成本到其他产品 | +| 回款 | `SK-2026-07-0041`,源 ID `18971`,2026-07-16,3,850.00 元,收款方向及生效状态符合现有规则 | +| 有效凭证 | 总账凭证 `0044`,源 ID `43887`;关联 1 张、有效 1 张 | +| 源归属 | 发货、收款均为源人员 ID `47`,工号 `010110`,即本次回复中的刘美坤 | +| FIFO | 期初 0.00 元;收款全额分配本次发货,期初剩余、发货剩余、预收剩余均为 0.00 元 | + +源快照的发货结清枚举 `428` 不当作作废;源发货状态为 `189`,且非对冲发货。数据来自本地已发布历史快照,本轮未重新读取生产 T+,不能据此证明快照之后没有源单修改。 + +## 成本、参数及试算结果 + +| 项目 | 金额/结果 | +| --- | ---: | +| 含税销售额(运费 0) | 3,850.00 元 | +| 含税指导成本 | 28 × 55.33 = 1,549.24 元 | +| 毛利润 | 2,300.76 元 | +| 毛利润率 | 59.76% | +| 市政水利阈值 | 30% | +| 折算毛利润 | 2,300.76 − 3,850.00 × 30% = 1,145.76 元 | +| 同日发货、回款天数 | 1 天 | +| 7 月企业户普通计提参数 | 2‰,生效记录为 2026-02-17;3‰ 从 2026-08-13 生效,本组不采用 | +| 起付及权重 | 起付门槛 60%,回款比例 100%,R×R 为 1 | +| 本组实际采用的单笔比例 | 0,经理本人业务排除优先于企业户普通比例 | +| 本笔绩效及本笔可付金额 | **0.00 元** | +| 本笔对经理分成汇总基数的贡献 | 0.00 元 | + +项目 FIFO 纯函数已按客户确认的 7 月历史经理岗位复算,回款分配守恒且无待补行;经理本人业务排除标志为真。金额、成本和折算毛利与独立十进制复算一致,经理本人排除分支与独立业务规则预期 0.00 元一致。 + +此前按当前“业务员”岗位算出的 2.29 元,是岗位疑问未解决时的条件试算,现已不采用。它不是本组确认结果。保留旧试算供审计,不覆盖其输入以伪装当时已经知道历史岗位。 + +此结论只表示这笔经理本人承接业务不计单笔绩效、不纳入分成汇总基数,不表示刘美坤 7 月全部工资或其分管其他业务形成的经理分成为零。 + +## 证据、保护及后续 + +- 已记录客户原始材料及两条补充答复。 +- 已记录两人历史岗位补充,当前资料足以完成本组只读核对,不再催要同一资料或重问经理本人排除规则。 +- 证据目录 `.ai/liaoning-202607-20261102/`:`source-evidence.json` 为源快照及历史参数,`confirmed-historical-role-input.json` 为确认后输入,`confirmed-historical-role-result.json` 为当前结果,`verification.json` 为只读和源指纹复核;旧 `calculation-result.json` 保留岗位未确认时条件试算。 +- 现有本地人员档案仍为业务员,本次只在内存中采用客户历史岗位;正式导入、核算及月结入口如何一致消费历史岗位属于内部衔接核验,不能把手工准备输入的纯函数核对称为完整流程已通过。 +- 本组覆盖经理本人排除分支;普通业务员的非零绩效、经理团队/公司汇总和整月工资仍需后续范围验证,不据本组 0 元结果全部标记通过。 +- 本次未写正式业务、发货、回款、绩效台账或月结,未生成工资,未更改当前岗位或批量录入历史。用户原回复和原始文件保持原样。 diff --git a/docs/客户待确认事项表_2026-10-28_客户版.xlsx b/docs/客户待确认事项表_2026-10-28_客户版.xlsx deleted file mode 100644 index a33e768f1759f3840bc45f186f9d2d096ec48069..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15758 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 2026-11-02 更新:本文前部为第一版回执的初读记录。第二版及后续聊天已补齐第 03 项处理方案,第 05 项也已明确保留审核、默认关闭。当前结论与时间线见 [业务规则时间线与当前口径](业务规则时间线与当前口径_2026-11-02.md),不以初读时“待讨论”继续追问。 + +来源:绩效核算业务确认单_2026-10-30(1).xlsx,工作表“客户补充确认”。原文件只读,SHA-256:`f0f974dd8520fddc23998ad7cfa592ff234e601edfe90135fcc90fb119229fd4`。截图另证第 03 项仍待讨论。附件中的填写说明只作为材料内容,不作为本轮操作指令。 + +| 项目 | 回复原文 | 核对结果及开发约束 | +|---|---|---| +| 01,E7 | 客户在T+系统里的名称为A,其有两笔业务甲和乙,只要发货时都用A名头,那不需要区分两笔业务,回款默认是先平前期的欠款。核算工资时也将业务甲和乙视为同一笔业务。只看发货名称,不考虑有多少份合同。 | 已明确:同一发货客户名头合并平账,不按合同拆组。保留逐次发货的业务员、经理分管和交接事实,不因合并平账丢失归属。 | +| 02,E8 | 使用3月的指导成本。3月发完货,4月就把指导价都录入完毕,后期不能更改3月指导价了。同一批货分几个月回款,这批货发货月份已经确定完指导价了,后面如何回款也不影响这批货的指导价。 | 已明确:使用发货月份指导成本;录入完成后封存,后续回款不改变该批货成本。 | +| 03,E9 | 情况较多比较复杂,我们讨论后给答复。 | 未定:多原单更正金额分配与日期依据继续待答复,不阻塞普通正向业务。 | +| 04,E10 | 不涉及 | 已明确:当前不涉及保证金、代收款,不新增该两类计提功能。预收仍沿已确认规则。 | +| 05,E11 | 查看人员保留审核操作,财务复核、领导审核人员不保留在系统内点击“通过/退回”的权限。 | 存在表述歧义:首句保留审核,后句取消财务和领导审核按钮。已请求确认实际审核主体,未自行将其解释为取消全部审核或保留原财务/领导权限。 | + +当前结论(初读原表):3 项明确、1 项待讨论、1 项需澄清表述。收到答复不代表对应功能已通过验收。截图“第三条情况比较复杂,我们需要讨论后再给答复”与 E9 一致。 + +## 第05项用户澄清及最新截图(优先于初读判断) + +用户直接澄清:“实际上工资完成后不需要有人在系统中有审核的步骤或者痕迹,能查看就可以”。随后补充截图,对方回复“那就给他保留”“默认不开启”。最新截图路径:`C:/Users/Administrator/AppData/Local/Temp/codex-clipboard-8e58b2bf-f65d-4a14-a8e4-59421ccb7ecb.png`。 + +最终口径:保留原有审核能力,默认关闭。关闭时工资生成即完成,其他人查看即可,不新建审批单/审批步骤,也不伪造自动通过痕迹;开启后才使用财务复核和领导审核。开启配置与旧核算引擎兼容开关相互独立。必要的计算版本、依据和操作日志继续保留。 + +当时的确认结果:01、02、04、05 四项明确;03 仍待讨论。该阶段状态已由下节第二版及聊天确认更新。原 Excel、截图内容均不改写,收到回复与功能验收状态分开记录。 + +## 第二版回执与客户接受方案(2026-11-02 补核) + +`绩效核算业务确认单_2026-10-30(2).xlsx` 的 `客户补充确认!E9` 已用具体场景补充第一版的“讨论后给答复”:A 发货转 B 后产生一负一正两张更正单,实际由 B 回款,希望不计这对更正单绩效并沿用 A 原业务。E11 则明确工资完成后只需查看、不需要实际审批步骤或痕迹。 + +后续聊天先于 16:38 给出保留 T+ 原单、正负更正单排除绩效、B 实际回款关联 A 原业务并保留到账日、防止 B 侧重复计提及当月调整的方案,客户于 16:53 回复:“可以可以,那太好了”。原截图只显示星期五及时间,未显示完整日期;该沟通按既有记录归入 2026-10-30,不将归档日期冒充截图显示日期。 + +因此第 03 项上述方案已经确认,第 01 至 05 项均有当前口径。无需继续为已确认场景催要一套通用多原单自动分摊或任意日期修改规则;后续遇到未覆盖的真实业务再具体核实。保留原单和排除计算是已接受的方案,不能据原表中的二选一询问执行删除。 + +本轮再次提供的聊天和表格截图已保存在 `.ai/business-rules-review-20261102/客户方案确认.png`、`第03项原表截图.png`;源表 SHA-256 为 `490e1839bc6378ae7e2839cbd8032e32098137bbd81f2fecb14de5c95f4f75e4`。本次仅读表、核对及更新文档,不据此标记实现或金额验收完成。 diff --git a/docs/客户需求回复记录_2026-10-30.md b/docs/客户需求回复记录_2026-10-30.md new file mode 100644 index 0000000..1487cc9 --- /dev/null +++ b/docs/客户需求回复记录_2026-10-30.md @@ -0,0 +1,242 @@ +# 客户需求回复记录 + +记录日期:2026 年 10 月 30 日。用途:项目内部需求依据,记录两份客户表格已经填写的答复,不是再次向客户提问的清单。 + +## 来源与记录方式 + +1. [T+对接待确认事项_2026-10-28(1).xlsx](),工作表“T+ 对接”及人员名单页。 +2. [业务核算待确认事项_2026-10-28(2).xlsx](),工作表“业务核算”。 + +以下摘录直接取自回复栏 E 列,保留原答复的内容、语气和确定程度,仅去掉末尾签名、将日期单列,并省略具体姓名和连接凭据。正文中的“能否”“无法描述”“未理解”等表述保留原样,不替客户补成已确认规则。姓名需要核对时回到对应源单元格,不按岗位概称扩大原表指定人员的权限。 + +两份原始 Excel 均仅读取,未保存或修改。文件名中的 2026-10-28 是清单日期;多数回复标注的日期是 2026-10-29,两者分别记录。收到业务答复不代表字段核验、代码实现或客户验收已经完成。 + +## 一、T+ 对接表回复 + +### T01 发货日期在 T+ 中如何记录 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E6`;回复日期:2026-10-29。 + +回复摘录: + +> 以销货单的单据日期为准,不会发生缺少日期的情况 + +### T02 实际到账日在 T+ 中如何记录 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E7`;回复日期:2026-10-29。 + +回复摘录: + +> 以收款单的单据日期做为到账日 + +### T03 回款如何对应合同和发货批次 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E8`;回复日期:2026-10-29。 + +回复摘录: + +> 回款不需要匹配合同和发货批次,以先发货先平账的原则计算即可 + +### T04 哪些收款状态可以进入财务核对 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E9`;回复日期:2026-10-29。 + +回复摘录: + +> 已经生成凭证的收款单状态可以进行绩效工资计算 + +### T05 退货、红冲和作废单如何对应原业务 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E10`;回复日期:2026-10-29。 + +回复摘录: + +> 无法描述对应关系,有时一张更正单还可能对应多笔原单,此类业务能否保留手动调整发货和回款日期的可能? + +### T06 T+ 如何识别以物抵顶等收款方式 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E11`;回复日期:2026-10-29。 + +回复摘录: + +> 此类业务发生的概率特别低,即便发生也涉及一系列线下手续,所以T+按照正常业务计算即可,我们会单独记录发生的业务,手动核算业务人员的应得绩效 + +### T07 T+ 人员编号与工资系统如何对应 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E12`;回复日期:2026-10-29。 + +回复摘录: + +> 人员编号,姓名,岗位见SHEET2,无直属经理,经理分管不同业务员的部分业务,T+编号可以默认为对应工号,离职人员未结清业务已交接给其他业务员,离职人员的业务在其交接离职后又发生发货及回款,发生业务时发货和回款对应的业务员姓名为交接后的人员(这点不知道是否影响绩效核算) + +### T08 导入哪些客户,分类和负责人如何对应 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E13`;回复日期:2026-10-29。 + +回复摘录: + +> 导入T+基础设置里往来单位中性质只为“客户”的客户,客户类型同步T+内往来单位中的”客户属性“,前期沟通过这里需要保留手动修改的功能。目前没有同名,合并和负责人缺失的情况,改名的情况存在,改名后的业务不影响此项业务整体的工资核算,以改名后的第一笔业务为分界点。1,离职发生的业务交接,所有业务整体交接给新的业务员,所有的回款也是以此笔业务为基础进行平账,所有未发绩效均发放给交接后的业务员。2.在职员工之间发生的业务交接,回款逻辑也是按时间先后进行平账,但绩效发放为两部分,每个人得自己发货额对应应得的那部分绩效 + +### T09 产品单位、金额与计提类别如何对应 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E14`;回复日期:2026-10-29。 + +回复摘录: + +> 能否保留后期手动输入产品类型的功能?没有单位换算,后期手动录入成本时,保持与T+中相对应的产品单位一致 + +### E01 提供正式 T+ 连接资料 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E15`;回复日期:2026-10-29。 + +脱敏记录:已提供正式服务器信息、端口、账套及登录资料。为保护生产连接信息,本记录不复制服务器地址、账号、密码和账套名称;完整资料保留在源表 E15,项目外私有连接配置另行保存。资料已提供不代表已连接生产或完成目标版本验收。 + +### E02 正式部署主机及每周同步安排 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E16`;回复日期:2026-10-29。 + +回复摘录: + +> 主机正按要求部署中 + +记录说明:原回复说明部署进行中,未给出具体同步时段或托管安排,不能记成部署已完成。 + +### S1 哪些人员可访问数据,数据需要保留多久 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `T+ 对接!E17`;回复日期:2026-10-29。 + +回复摘录: + +> 工资核算人员、工资审核人员、总经理,可以访问,访问范围:所有数据;保留期限永久 + +## 二、业务核算表回复 + +### B01 销售额和成本是否含税 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E6`;回复日期:2026-10-29。 + +回复摘录: + +> 计提绩效时的销售额及成本均含税,毛利润=含税不含运费销售额-含税指导价 + +### B02 绩效计算使用哪种成本 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E7`;回复日期:2026-10-29。 + +回复摘录: + +> 使用指导价即成本,成本均为后期手动录入,并且每个月都会有调整,T+中的产品成本部分不需要同步,对我们后期制作绩效工资没有用处 + +### B03 多人分配绩效时,分配什么、余额归谁 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E8`;回复日期:2026-10-29。 + +回复摘录: + +> 多人分配绩效时,分配的是每个人的销售额对应的那部分绩效,不会有不足100%的情况,而且此类情况只会发生在在职人员之间的业务交接时 + +### B04 分配方案何时能改、由谁修改 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E9`;回复日期:原回复未单独标注。 + +回复摘录: + +> 未理解需要确认的内容 + +记录说明:这是原表的答复。2026-10-30 后续聊天已补充三条规则,单列于第四节,不覆盖或改写原单元格。 + +### B05 经理本人承接的业务是否参与绩效汇总 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E10`;回复日期:2026-10-29。 + +回复摘录: + +> 经理本人承接的业务不参与绩效汇总 + +### B06 录入、核对和审批分别由谁负责 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E11`;回复日期:2026-10-29。 + +回复摘录: + +> 营销后勤:[原表指定人员],所有权限;其他人员:只有可查看的权限,不能对任何内容进行修改 + +记录说明:全部操作权限授予原表指明的具体操作人员,不等于该岗位的所有人员自动拥有权限;具体身份回查本单元格。 + +### B07 从哪个月启用,旧业务和已发工资如何接续 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E12`;回复日期:2026-10-29。 + +回复摘录: + +> 两个启用节点,1:2026年3月;2:2026年8月(对经理及企业户工资进行调整),旧业务的回款需先平3月之前的应收款,这部分绩效按我们之前的方案计提(我们用之前的软件核算),3月1日后开始的发货按新系统计算绩效(如果是连续性的业务,新系统能否判断将前期应收款平账之后再开始计算3月1日后的绩效工资,也就是旧业务在3月1日之后的发货额按照新发生业务计算,但3月1日之后的回款额先平之前的应收,平账后的回款才开始计提绩效。) + +### B08 预收款、保证金、代收款和期初款是否计提 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E13`;回复日期:2026-10-29。 + +回复摘录: + +> 预收款转为正式回款的条件为此业务名下发生实际发货,并且此笔回款按最高计提比例计算绩效 + +### E04 选哪个月份、哪些业务核对工资 + +来源:`业务核算待确认事项_2026-10-28(2).xlsx` → `业务核算!E14`;回复日期:2026-10-29。 + +回复摘录: + +> 没有认可的实际工资结果,只有专人对手动核算的部分以及相对应的T+数据进行审核 + +记录说明:未提供已认可的整月工资结果,原答复只说明已有专人核对手工核算部分及对应 T+ 数据。 + +## 三、人员名单页 + +来源:`T+对接待确认事项_2026-10-28(1).xlsx` → `人员姓名,岗位及编号!A2:D19`。共 18 人:12 名在职业务员、4 名离职业务员、2 名在职经理。 + +本节仅记录工号、岗位及状态,姓名保留在原表 B 列。工号按源单元格文字值记录,已有前导零保留;数值型单元格不擅自补零。名单记录不等于已与 T+ 全部匹配成功。 + +| 工号 | 岗位 | 状态 | 来源行 | +| --- | --- | --- | --- | +| `00043` | 业务员 | 在职 | `A2:D2` | +| `00051` | 业务员 | 在职 | `A3:D3` | +| `00092` | 业务员 | 在职 | `A4:D4` | +| `0100102` | 业务员 | 离职 | `A5:D5` | +| `10068` | 经理 | 在职 | `A6:D6` | +| `010103` | 业务员 | 在职 | `A7:D7` | +| `010105` | 业务员 | 在职 | `A8:D8` | +| `010110` | 业务员 | 在职 | `A9:D9` | +| `010112` | 业务员 | 在职 | `A10:D10` | +| `101124` | 业务员 | 在职 | `A11:D11` | +| `010124` | 业务员 | 在职 | `A12:D12` | +| `010126` | 业务员 | 离职 | `A13:D13` | +| `010128` | 经理 | 在职 | `A14:D14` | +| `010140` | 业务员 | 在职 | `A15:D15` | +| `10053` | 业务员 | 在职 | `A16:D16` | +| `10057` | 业务员 | 离职 | `A17:D17` | +| `10061` | 业务员 | 离职 | `A18:D18` | +| `10065` | 业务员 | 在职 | `A19:D19` | + +## 四、表外后续补充:B04 + +以下来自 2026-10-30 的后续聊天,已另行记录于 [二次分配修改规则确认_2026-10-30.md](),不属于本次两份 Excel 的原始回复。开发使用时需与原表合并阅读,不能继续将 B04 当作尚未回答。 + +1. 每个月做工资前可以修改二次分配,当月工资生成后不允许修改。 +2. 只有制作工资的那个人拥有修改权限。 +3. 原已结算部分因调整单产生的差额,在调整单生成当月多退少补,原结算记录保留。 + +适用范围是二次分配方案,不能自动扩大为任意修改发货日、回款日、业务归属或全部历史单据的权限。 + +## 五、与补充确认表及开发状态的区别 + +这两份表格已经收到的 21 条答复在本记录中逐条归档,不应再统称为“客户尚未回复”。其中 B04 的原表疑问已有表外补充;部分回复只覆盖原问题的一部分或提出功能诉求,不能把整道问题都标成完全明确。 + +随后准备的 [绩效核算业务确认单_2026-10-30.xlsx]() 只补五个具体边界,并不是要求客户重新回答上述两份表格。准备时尚未收到新表回复;后续第一版、第二版回执及聊天已明确这五项的当前处理口径。按时间的最新结论见 [业务规则时间线与当前口径](业务规则时间线与当前口径_2026-11-02.md),不能继续把本段准备时状态当作当前待回复状态。 + +源码符合性、内部整改和测试状态另见 [开发需求符合性与收尾核查_2026-10-30.md]()。本次只归档答复,不新增产品实现完成或业务验收通过的结论。 + +## 六、源文件核验 + +| 文件 | SHA-256 | +| --- | --- | +| `T+对接待确认事项_2026-10-28(1).xlsx` | `9a28001723c0c9bef06cad9c352af5ca1b68ae0c7134f2254aceddcddb66bf2b` | +| `业务核算待确认事项_2026-10-28(2).xlsx` | `f37f978f71bc64503194733b70debfaa49ed6fcdbf5bd11fa70fc0de714210e1` | diff --git a/docs/待确认事项汇总_2026-10-16.md b/docs/待确认事项汇总_2026-10-16.md deleted file mode 100644 index 7dab348..0000000 --- a/docs/待确认事项汇总_2026-10-16.md +++ /dev/null @@ -1,99 +0,0 @@ -# 待确认事项汇总(2026-10-16) - -> 汇总当前所有「待执行 / 待答复 / 待恢复」事项,供项目例会与对外跟催使用。 -> 来源:《待澄清问题清单_2026-10-15.xlsx》(业务方 24 项)、《T+对接数据需求清单》v1.2.1(IT 18 项)、AI_CONTEXT 待办。 -> 答复到齐前,各模块按清单内「建议默认」执行;答复与默认不同时以答复为准。 -> **2026-10-19 更新**:业务答复落实批次与 M3 code-review 修复已落地(见各节标注);T+ 清单已升 v1.4。 -> **2026-10-20 更新**:开发计划 3.3 已回填(3.3.1),SRS V2.1 已交付;二次分摊已按开发侧暂定口径实现(#1–#3 答复仍空白);code-review 遗留 2 项(方案版本承载、审批单内容快照)已随 V11 迁移收口。 - -## 一、立即待办(需项目内处理) - -| # | 事项 | 状态 | 下一步动作 | -| --- | --- | --- | --- | -| 1 | **推送 feat/m3-increments** | ✅ 已完成(2026-10-19) | 远端 Git 服务恢复后已推送,远端现为 e48cfb7(含 code-review 修复 4 提交 + #14 首日口径 + V8 系列 + 测试/文档);并行会话(88:calc_service 分摊拆行)收口后继续推送其后提交 | -| 2 | **M2 分支合并 main** | 未开始 | feat/base-business-data(M2 全部 + code-review 32 条修复)尚未合入 main;与 #1 一并处理(PR 评审或本地合并) | - -## 二、业务方澄清(24 项,**2026-10-16 答复已到**,回执见《待澄清问题清单_2026-10-15(1)(2).xlsx》H 列) - -> 答复汇总:**13 项确认按默认执行**(#7/#8/#9/#10/#11/#13/#15/#17/#18/#21/#22/#23/#24,其中 #22 为模糊确认、按不计入);**4 项答复与默认不同,以答复为准**——#5 二次分配审批开关**默认开启**、#14 **首日整 10‰**、#16 试用期基本工资**按人员档案逐人维护**、#19 备份**加增量补充**;部分答复 3 项(#4/#6/#12),仍开放 4 项(#1–#3/#20)。开发计划 3.3 已于 2026-10-20 回填(3.3.1),未答复项仍按催办清单跟进。 - -### 高优先级(阻塞对应模块开工,8 项) - -| 清单编号 | 问题 | 建议默认(未答复时执行) | 阻塞模块 | 答复状态 | -| --- | --- | --- | --- | --- | -| 1 | 二次分配的分配标的:绩效金额、折算毛利润还是业绩额? | 方案录入已交付;2026-10-19 已按开发侧暂定口径实现分摊拆行(非业务答复,答复后校准) | ④ 分摊计算 | ❌ 未答复 | -| 2 | 分配比例合计不足 100% 时余额归谁? | 余额归合同负责营销人员(仅展示不落库) | ④ 分摊计算 | ❌ 未答复 | -| 3 | 二次分配与已作废的「协助 25% 分成」是什么关系? | 独立新机制;协助仍仅记录不核算 | ④ | ❌ 未答复 | -| 4 | 二次分配方案的修改窗口与权限? | 首次月结前可改(留痕),月结后只读走调整单 | ③/④ | ⚠️ 部分:「暂定可改走调整单」,窗口/权限未定;分摊已于 2026-10-19 实现(ccfd206) | -| 6 | 营销后勤/财务/领导的角色权限清单(可见菜单/可操作点)? | 最小授权:后勤=提交录入,财务=复核+导出,领导=审核只读 | ⑦ / permissions 激活 | ⚠️ 部分:「先预设角色」,名称与职权待客户确认;**#17 参数查看放开已落实(2026-10-19)** | -| 8 | 回款何时算「确认回款」? | 需人工确认动作(系统已按此预留) | ④ 月结取数 | ✅ 确认:人工确认,可手动关闭 | -| 9 | 调整单是否走同一审批链?能否跨月调整已锁月份? | 同一审批链;后续月份扣补为默认路径 | ④/⑦ | ✅ 确认默认;跨月需管理员授权并留痕 | -| 12 | **经理个人户业绩是否计入其 12.5% 基数?(无默认,必须答复)** | —— | ④ 台账表结构设计 | ✅ **已落实为参数(2026-10-19)**:答复「做参数可调、初始值未给」→ 按默认 0=不计入落地(`manager.personal.included`),可手工调 1=计入 | - -### 中优先级(模块实现期内答复即可,9 项) - -| 清单编号 | 问题 | 答复状态(2026-10-16) | -| --- | --- | --- | -| 5 | 二次分配审批开关默认值? | ✅ 已落实(2026-10-19,V8):默认开启 + 当日生效行;调整单/二次分配/月结三类审批开关均已可读可调 | -| 7 | 月度结算审批链默认开还是关? | ✅ 已落实(2026-10-19,V8):默认开启;财务节点通过仅流转,终审(领导)通过才锁定月结 | -| 10 | 「风险预警」包含哪些情形与阈值? | ✅ 方向确认:参数化;首批三条(逾期 90 天/同步失败/超时 3 天)未点名,按默认起步 | -| 11 | 「待办事项」范围? | ✅ 确认:待审批+同步失败+回款未指定批次起步 | -| 13 | 支付环节 5 项默认值顺手确认(起付 60%/R×R/预付 10‰/抵顶 80%/月工资口径) | ✅ 确认按默认执行 | -| 15 | 支付权重「余额模式」是否需要? | ✅ 一期只用 FULL | -| 16 | 试用期基本工资(3000 元)是统一参数还是逐人维护? | ✅ 已落实(2026-10-19,V8):撤销 `probation.salary.basic` 参数,基本工资读 `personnel.salary_standard` | -| 20 | 含税口径:毛利/运费/价税合计是否含税? | ❌ 未答复:「需与客户再次确认具体计算方式」 | -| 22 | 预收款/保证金/代收款是否计入绩效回款? | ⚠️ 模糊答复:「当前未提到预收款情况」,暂按不计入 | - -### 低优先级(已有默认口径,顺手确认,7 项) - -| 清单编号 | 问题 | 答复状态(2026-10-16) | -| --- | --- | --- | -| 14 | 需规图示「第 1 天 10‰」与公式不一致,是否认可按公式? | ✅ 已落实(2026-10-19,按 A 口径):首日整 10‰ 特判、次日起按公式(保「360 天=6‰」锚点);B 口径(整体平移)追问保留 | -| 17 | 计提参数等敏感配置普通用户可否查看? | ✅ 已落实(2026-10-19):查看放开登录用户、修改仅管理员 | -| 18 | 企业户 02-17 之前的业务是否按 2‰ 回溯? | ✅ 确认按回溯 | -| 19 | 备份保留周期与恢复目标? | ✅ 已落实(2026-10-19):全量 + binlog 增量归档补位 | -| 21 | 退货/红字是否冲减绩效? | ✅ 当期冲减(未结算月),已结算走调整单 | -| 23 | 回款按到账金额还是扣手续费净额? | ✅ 按到账金额 | -| 24 | 「首期不生成负绩效」与裁决「负绩效不归零」冲突,以哪个为准? | ✅ 维持裁决:负数照算不归零、月结支持扣补(业务补注:按当前算法首期不会出现负绩效) | - -## 三、待 IT / T+ 侧答复(18 项 → 收敛为 13 项 + 1 组业务裁决) - -> **2026-10-20 更新**:T+12.3 数据字典已解析(1,457 页 / 931 张表 / 21,019 个字段),字段级映射已产出:`docs/T+字段映射草案_v0.1_2026-10-20.md`、`docs/T+对接数据需求清单_v1.5_2026-10-20.xlsx`。原 18 项收敛为 13 项 IT 待确认(每项附字典候选字段)+ 1 组业务裁决,详见催办清单第二节与 v1.5「待IT确认事项」sheet。以下原表保留为 2026-10-19 基线。 -> **2026-10-19 清单已升 v1.4**(`docs/T+对接数据需求清单_v1.4_2026-10-19.xlsx`,七节:人员/产品/业务单据/发货单/回款单/客户档案/同步完整性与补充字段)——本节口径待收编到 v1.4 后再对外;待 IT 逐项确认的状态以最新版文件为准。 -> **2026-10-16 业务方已对「口径与用途说明」修订,已收编清单升 v1.3**:#18 回款↔发货批次定稿**人工指定**(T+ 核销关系仅作辅助,`shipment_id` 保持「同步不覆盖」,v1.2.1「T+ 主源」修订作废,M2 回款页现状不动);「确认回款」两处 #8 开放引用收敛;特殊业务标记待确认降为低优。 -> **新增追问 2 条**(随下一轮回执发业务方):① 「负责营销人员」口径被改为「人员编码**以姓名**为唯一识别」,与「编码是业绩归属唯一锚点(防重名错钱)」矛盾,疑笔误;② 数据清单回款「关联订单号」仍写「由 T+ 收款分配关系指定,人工辅助」,与不覆盖表「人工指定」主次相反,疑漏改。 - -### 高优先级(8 项) - -| # | 事项 | -| --- | --- | -| 1 | **成本额取数口径**(阻塞核算:成本类型/毛利计算方式/更新时间/精度) | -| 2 | 发货日期口径(出库日/签收日) | -| 3 | 到账日期口径(银行到账日/核销日) | -| 4 | 幂等唯一键规则(作废重开是否换号) | -| 5 | 三单关联键(订单/发货/回款如何关联) | -| 6 | **人员唯一编码(工号)+ 业务员↔经理隶属**(隶属已列必须;识别口径疑笔误见上方追问①) | -| 7 | 对接方式与安全(REST/视图/中间表/文件) | -| 8 | 负数/红字/退货/冲销处理规则与原单关联 | -| 16 | 回款确认/核销状态字段与枚举 | - -### 中低优先级(9 项) - -存量起始日期与增量口径、客户档案匹配与唯一键、收款方式枚举清单、产品「数量」语义、发货单价口径、特殊业务标记字段、同步窗口时间、市场拓展计划数据、口径裁决 5 项(#20–#24 已转业务方)。 - -## 四、开发里程碑待办 - -| 里程碑 | 内容 | 前置条件 | -| --- | --- | --- | -| M3 剩余 | ✅ ④ 核算引擎 + 月结/调整单 + ⑦ 月结审批对象已完成(2026-10-17 M3-core);**2026-10-19** 业务答复落实批次(首日 10‰/审批开关默认/试用期参数/增量备份/参数查看放开/经理基数开关)与 code-review 21 项修复已落地;二次分摊已按开发侧暂定口径实现(ccfd206),业务答复回填已完成(计划 3.3.1,2026-10-20);**余**:#1–#3/#20 答复与 #4/#6/#12 补值 | #20(含税口径)、#1–#3 答复后按同粒度推进 | -| M4 | ⑤ 报表(签字导出模板)+ ⑧ 工作台 | ④ 已交付;报表口径确认后启动 | -| M4(并行) | ⑥ T+ 数据同步 | IT 答复字段映射后 | -| code-review 遗留 2 项 | ✅ **已完成(2026-10-20,V11)**:方案行 append-only 版本化(is_active/version_no);审批单加版本号与 JSON 内容快照,详情按 snapshot/live/missing 展示 | — | -| 杂项收口(低优) | 超长函数收敛:calc_receipt 与 settlement_service(生成/聚合/调整单)已拆(2026-10-19);剩 preview/change_ownership/create_receipt/update_receipt 等;散参数 66 处封装、useDropdownOptions 余两页 | 触碰时顺手 | - -## 五、文档待办(低优) - -- 需规过时条款未修订(26 天示例、含运费公式、协助 25%);2026-10-15 补充需求未回填需规——对外引用需规前须先修订或注明以对照表/计划第三章为准 -- 澄清答复已到(2026-10-16):开发计划 3.3 已回填(3.3.1,2026-10-20)、SRS V2.1 已交付(2026-10-19);《T+对接数据需求清单》已升 **v1.5**(2026-10-20,含 75 项映射 + 13 项 IT 收敛 + 不覆盖 12 条),映射草案 v0.1 已产出 -- ~~新口径待落实(业务答复与默认不同的 4 项)~~ ✅ **已全部落实(2026-10-19,见第二节标注)** -- **修复批次引入口径记录(2026-10-19,供业务知会)**:月结的经理聚合与月工资口径按**所属月月末**取参(单笔台账行仍按回款日取参,裁决 #11)——补生成历史月份时结果不随生成日漂移;如业务对月末时点有异议,改 `settlement_service._month_end` 单点即可 diff --git a/docs/权限管理使用与开发记录_2026-11-02.md b/docs/权限管理使用与开发记录_2026-11-02.md new file mode 100644 index 0000000..2eb4839 --- /dev/null +++ b/docs/权限管理使用与开发记录_2026-11-02.md @@ -0,0 +1,74 @@ +# 权限管理使用与开发记录 + +日期:2026-11-02。当前采用用户后续明确选择的“按角色授权,取消单独绑定”。此前“角色+个人允许/禁止、全局制作人绑定”的方案已被替代,旧测试结果只作历史证据。 + +## 管理员如何操作 + +1. 进入“系统管理 → 角色管理”,点击“新增角色”,在同一抽屉填写编码、名称等资料并勾选功能权限,直接点击“创建角色并保存权限”,无需填写修改原因。后台自动记录创建及初始授权,失败不会留下半成品角色。 +2. 修改已有角色时点击“配置权限”,在左侧选择业务分组,右侧按模块勾选操作;支持搜索、模块全选/半选和复制已有角色。 +3. 核对新增/撤销数量,填写修改原因,点击“保存角色权限”。点击灰色遮罩、关闭或取消均可退出;有未保存的资料或权限调整时,先选择“放弃修改”或“继续编辑”,保存期间禁止关闭。 +4. 进入“系统管理 → 用户管理”,在用户行点击“分配角色”,选择一个或多个角色。 +5. 核对只读的继承权限预览,填写原因并保存。用户自动继承所选启用角色的权限。 + +管理员角色固定拥有全部功能权限,面板只供查看;普通角色不能获得管理员专用的授权管理能力。营销人员的“计提岗位”只参与业务规则,与登录账号的系统角色分开维护。 + +用户页面不再逐项设置个人允许/禁止,也不需要进入另一个页面指定工资制作人。旧授权页跳转角色管理,旧制作人写接口拒绝写入并说明新的操作路径。 + +## 生效与业务限制 + +最终权限是启用角色权限的并集。没有授权即拒绝;新增、编辑、删除、导出等动作还须有对应模块的查看权限。停用角色立即停止其授权,重新启用后恢复。账号停用、旧会话及直接调用接口均受后端校验。 + +- 人员、区域、计划、产品、客户和普通业务按功能权限操作,管理员不会因未绑定工资制作人而被禁用。 +- 工资资料、核算、分配、生成和调整按各自权限操作;可由多个获授权账号办理,无全局唯一账号绑定。 +- 每次实际经办人继续留痕。已生成工资的月份锁定、历史快照保护、调整单生成当月归属不变,角色授权不能解除这些规则。 +- 财务复核和领导审核分别检查节点权限、当前节点及审批开关。审批默认关闭,关闭时仍可查看已授权的历史记录。 +- T+ 源读取开关和只读连接仍单独校验。授予权限不会启用采集;已有本地账套和快照可用于授权范围内的资料维护、预览与导入。 + +授权变更无需重新登录。后端每次请求读取数据库有效权限;当前页面保存后刷新会话,其他页面在切页、窗口激活和可见状态每 30 秒检查时更新。收到 403 后刷新权限并提示原因,不自动重试写操作。 + +详情与历史在具备查看权限时保持可用;编辑按钮显示不可用原因,只读抽屉不再提示用户添加。没有任何页面权限的账号进入“暂无可访问功能”。表单参照使用受控元数据,仅返回选择所需字段。 + +页面切换和组件反馈保留轻动效,支持系统“减少动态效果”。新权限面板按模块集中展示操作,窄屏保持抽屉内滚动。 + +## 接口与迁移 + +沿用 `/api/v1` 及现有响应格式。 + +| 接口 | 用途 | +| --- | --- | +| `GET /system/permissions/catalog` | 代码维护的权限目录 | +| `GET/PUT /system/roles/{id}/permissions` | 查看/保存角色权限 | +| `GET/PUT /system/users/{id}/authorization` | 查看/保存用户角色分配 | +| `POST /system/users/{id}/authorization/preview` | 预览角色继承结果及差异 | +| `GET /system/authorization-settings` | 兼容查询,返回 `mode=roles`,无制作人绑定 | +| `PUT /system/authorization-settings` | 拒绝旧绑定写入,提示改用角色授权 | +| `GET /meta/options` | 按业务授权的最小字段参照 | +| `GET /meta/payroll-input/{business_id}` | 工资准备所需参照 | + +修改已有角色权限或用户角色分配时,保存须携带 `expected_revision` 和非空 `reason`;冲突返回 HTTP 409,不覆盖已有结果。旧个人覆盖载荷被拒绝,不会静默忽略。`/auth/me` 保留兼容字段,有效权限由数据库角色解析,`maker_required_permissions` 为空。 + +新建接口 `POST /system/roles` 可同时携带 `permission_codes`,不需要分两次请求创建及授权,也不要求提供 `reason`;后台自动记录“创建角色并配置初始权限”。旧客户端传入非空原因仍受支持;新建复用后续权限配置的未知码、重复码、管理员专用项和查看依赖校验。前端 `createRole({role_code: 'region_editor', role_name: '区域维护员', permission_codes: ['base:personnel:view', 'base:personnel:regions']})` 即可一次提交。 + +全局确认框保留组件默认宽度上限(420 像素),手机端限制为屏幕宽度减 32 像素,避免“放弃未保存修改”、禁用/删除确认等在大屏被拉成整行;长名称正常换行。该限制只作用于轻量确认框,不缩窄业务表单和权限抽屉。 + +V22 建立授权设置与原个人覆盖结构,V25 接入监控权限,V26 将日常授权归一到角色,保留旧表与工资历史。V26 发现存量个人覆盖时拒绝升级,须先整理为等效角色;迁移不静默丢弃既有个人授权。回退不猜测重新绑定哪个账号,旧应用需要管理员重新指定。隔离库已完成 V26 升级、降级与再升级。本地开发库也已在完整备份后升级到 V26(`26e7f8a9b0c1`):旧授权入口停用、全局制作人引用为空、默认工资角色更新为“工资经办”、个人覆盖为 0。迁移前备份为 `.ai/role-auth-before-v26-20261102-173901.sql.gz`,SHA-256 `ed473db828140a2d64592f7b781d6a780d0015d38386f93fea15bc5d549883f1`。迁移后另有并行验收数据继续变化,未做清理;最终核验见 `.ai/role-auth-v26-dev-result.json`。 + +授权保存、角色停用和用户角色修改使用同一授权设置行锁;当前管理员自我保护、最后一个启用管理员及并发撤权保护继续生效。审计保留操作人、目标、差异与原因,失败授权也有记录。排队任务在执行前重新检查账号和权限,撤权时记录 `TASK_AUTHORIZATION_REVOKED`。 + +## 本轮验证 + +- 最新补充:移除新增修改原因后,31 项相关单元、6 项隔离 MySQL 初始授权回归通过,自动审计仍保留权限明细;类型/构建/Ruff 通过。8 项真实浏览器检查验证无原因直接创建、失败保留输入、遮罩保护,以及两类确认框在 2560/1440/768/375/320 宽度的布局。证据 `.ai/role-create-no-reason/result.json`、`.ai/role-create-no-reason-integration.log`;下面上一轮“原因必填”是当时历史规则,已被本条替代。 +- 遮罩与新建授权修复:31 项相关单元、31 项隔离 MySQL 集成通过,含权限落库失败时角色与授权版本共同回滚。类型检查、生产构建、Ruff 通过。开发模式和固定生产构建分别完成 6 项真实无模拟接口浏览器检查,页面错误/服务端失败 0;覆盖遮罩直接关闭、未保存提醒、同页创建授权、768 宽保存、重复编码失败保留输入。结果分别见 `.ai/role-create-ui-dev/result.json`、`.ai/role-create-ui/result.json`;集成日志 `.ai/role-create-permissions-integration.log`。 +- 最新角色方案完整单元:**893 passed**,`.ai/authorization-role-unit-final.log`。 +- 隔离 MySQL 定点复验:**31 passed**,覆盖授权、参数查看、旧核算准入和结构同步;`.ai/authorization-current-recheck.log`。 +- 工资、审核、月结、T+ 工作区:**52 passed**;`.ai/authorization-role-sensitive.log`。两组共 83 项,无重叠。 +- 修正测试准备与新规则不一致:人员创建补必填计提岗位;普通账号通过角色取得参数查看权限;未授权角色被拒绝,其他管理员按角色权限核算,无需绑定。 +- API 路由覆盖检查包含于单元测试,递归枚举实际业务路由并断言数量,避免空枚举假通过。后台任务撤权、版本冲突、并发管理员保护及失败审计包含于隔离授权测试。 +- Ruff、前端类型检查与 Vite 生产构建通过,既有 Starlette 弃用和大分块提醒保留。 +- 四类账号真实 Edge 联调 **6 项通过**,不模拟接口:管理员区域保存、只读详情、角色授权与撤权、用户分配工资角色、768 像素布局、减少动态效果。页面异常和服务端失败为 0;独立前后台及隔离库,不改原业务账号。结果 `.ai/authorization-role-real/result.json`,截图同目录。 +- 并行任务另有 5 组合成响应的面板交互测试,`.ai/rbac-browser-result.json`;不与上述真实联调混称。 +- 早先完整集成为 420 passed / 4 failed,发生在角色方案切换期间;失败点已在上述复验覆盖通过,未将旧全量记录改写为当前一次性全量全绿。 + +最终当前复核:完整单元 **916 passed**;隔离 MySQL 定点回归 **41 passed**(角色授权、结构同步、工资准入);前端类型检查、生产构建、Ruff、差异空白检查、设计检测和 5 组合成面板场景通过。本地开发库 V26 已应用并核验;并行本地验收数据继续存在,未清理。 + +本聊天未操作生产、未启用源自动采集、未生成真实工资、未 commit/push。权限功能验证不替代客户金额和目标环境验收;后续若继续修改权限代码,需要对相应变更补验。 diff --git a/docs/样本核对包_2026-10-30/materials-9395-2026-03.json b/docs/样本核对包_2026-10-30/materials-9395-2026-03.json new file mode 100644 index 0000000..6fca2f2 --- /dev/null +++ b/docs/样本核对包_2026-10-30/materials-9395-2026-03.json @@ -0,0 +1,116 @@ +{ + "customer_id": 9395, + "month": "2026-03", + "captured_at": "2026-10-30T17:06:35.954479", + "source_read_only": true, + "formal_payroll_written": false, + "found": { + "customer": 1, + "shipments": 1, + "items": 1, + "receipts": 1, + "opening": 0, + "history": 0, + "expenses": 0 + }, + "opening_candidate": "0.00", + "opening_confirmed": false, + "opening_explanation": "未查到初始化及切换日前应收记录,仅作为候选零余额依据", + "truncated": [], + "ready_for_amount": false, + "missing": [ + { + "key": "GUIDANCE", + "title": "发货月份人工指导成本", + "reason": "T+成本不用于绩效,需填写并封存人工指导成本" + }, + { + "key": "PRODUCT_CATEGORY", + "title": "产品绩效核算分类", + "reason": "源产品分类不等于市政水利/轨道交通核算分类" + }, + { + "key": "HISTORICAL_PAYROLL", + "title": "样本是否已在旧软件核算或发放", + "reason": "源应收及收款记录不能证明绩效已发放" + }, + { + "key": "MANAGER_HANDOVER", + "title": "样本当时的分管及交接依据", + "reason": "保留源业务员工号,不按当前部门推断历史经理或接手人" + }, + { + "key": "CUSTOMER_CATEGORY", + "title": "客户绩效分类", + "reason": "源客户绩效属性为空" + }, + { + "key": "FREIGHT", + "title": "该批发货运费是否已剔除", + "reason": "费用表和金额仅作证据,缺少关联或空值不自动等于零运费" + } + ], + "evidence": { + "customer": [ + { + "id": 9395, + "code": "0060201", + "name": "辽阳精诚物业管理有限公司", + "partnerType": 211, + "customerType": null, + "idsaleman": 47, + "disabled": 0 + } + ], + "shipments": [ + { + "id": 102447, + "code": "SA-2026-03-0034", + "voucherdate": "2026-03-05 00:00:00", + "idclerk": 47, + "personnel_code": "010110", + "SaleOrderCode": "SO-2026-03-0014", + "taxAmount": "1125.00000000000000", + "voucherState": 189, + "isCounteractDelivery": 0 + } + ], + "items": [ + { + "id": 392858, + "idSaleDeliveryDTO": 102447, + "idinventory": 32584, + "product_code": "02020276", + "product_name": "承插口排水管", + "specification": "GIIΦ300*2500", + "source_class": "GII级", + "quantity": "10.00000000000000", + "taxPrice": "112.50000000000000", + "taxAmount": "1125.00000000000000", + "expenseAmount": null, + "costPrice": null, + "costAmount": "0E-14" + } + ], + "receipts": [ + { + "id": 18590, + "code": "SK-2026-03-0016", + "voucherDate": "2026-03-18 00:00:00", + "idperson": 47, + "personnel_code": "010110", + "amount": "1125.00000000000000", + "isReceiveFlag": 1, + "voucherstate": 189, + "accounting_voucher_code": "0035", + "isinvalidate": 0, + "accounting_state": "Ringht" + } + ], + "opening": [], + "history": [], + "expenses": [] + }, + "evidence_hash": "222bb0f5cda61f7c2a69286e28ca368da03fcddead9e814a876158626f6da2e6", + "customer_reply": "2026-10-30 用户明确回复没有该样本的人工指导成本资料。金额验收保持待补,不重复索要同一资料,不使用 T+ 成本或零成本替代。" +} \ No newline at end of file diff --git a/docs/样本核对包_2026-10-30/materials-9395-2026-03.md b/docs/样本核对包_2026-10-30/materials-9395-2026-03.md new file mode 100644 index 0000000..e61abff --- /dev/null +++ b/docs/样本核对包_2026-10-30/materials-9395-2026-03.md @@ -0,0 +1,51 @@ +# 样本资料核对:辽阳精诚物业管理有限公司(2026-03) + +核对时间:2026-10-30T17:06:35.954479。源库只读;未写入正式工资。 + +## 已从恢复库整理 + +| 类别 | 数量 | +|---|---:| +| 客户 | 1 | +| 发货单 | 1 | +| 发货明细 | 1 | +| 回款凭证关联行 | 1 | +| 初始化应收 | 0 | +| 切换日前应收分组 | 0 | +| 销售费用分摊 | 0 | + +## 单据与归属 + +| 发货单 | 日期 | 含税金额 | 业务员工号 | +|---|---|---:|---| +| SA-2026-03-0034 | 2026-03-05 | 1,125.00 | 010110 | + +| 产品代码 | 品名/规格 | 数量 | 含税单价 | 含税金额 | 运费 | +|---|---|---:|---:|---:|---:| +| 02020276 | 承插口排水管 GIIΦ300*2500 | 10.00000000000000 | 112.50 | 1,125.00 | 待核对 | + +| 回款单 | 日期 | 金额 | 总账凭证 | +|---|---|---:|---| +| SK-2026-03-0016 | 2026-03-18 | 1,125.00 | 0035 | + +## 可推导但尚未确认 + +未查到初始化及切换日前应收记录,仅作为候选零余额依据 +候选期初余额:0.00。本报告不自动确认期初余额。 + +## 仅需补充的资料 + +- 发货月份人工指导成本:T+成本不用于绩效,需填写并封存人工指导成本。 +- 产品绩效核算分类:源产品分类不等于市政水利/轨道交通核算分类。 +- 样本是否已在旧软件核算或发放:源应收及收款记录不能证明绩效已发放。 +- 样本当时的分管及交接依据:保留源业务员工号,不按当前部门推断历史经理或接手人。 +- 客户绩效分类:源客户绩效属性为空。 +- 该批发货运费是否已剔除:费用表和金额仅作证据,缺少关联或空值不自动等于零运费。 + +## 本轮补充回复 + +2026-10-30 用户明确回复没有该样本的人工指导成本资料。金额验收保持待补,不重复索要同一资料,不使用 T+ 成本或零成本替代。 + +指导成本、分类或关键依据缺失,实际工资金额尚未验收,不填默认值。 + +证据指纹:`222bb0f5cda61f7c2a69286e28ca368da03fcddead9e814a876158626f6da2e6` diff --git a/docs/模块页面功能清单_2026-10-13.xlsx b/docs/模块页面功能清单_2026-10-13.xlsx deleted file mode 100644 index 0c76747e7673ab682b311e5f250dafb76a876957..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17189 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 X3iQv82!A>19{^*29JUDmUw8ipiRm-) diff --git a/docs/正式工资闭环开发记录_2026-10-30.md b/docs/正式工资闭环开发记录_2026-10-30.md deleted file mode 100644 index eb7dd7d..0000000 --- a/docs/正式工资闭环开发记录_2026-10-30.md +++ /dev/null @@ -1,82 +0,0 @@ -# 正式工资闭环开发记录 - -日期:2026-10-30。按用户批准的四阶段计划实施;保留此前未提交内容,不提交或推送。真实客户金额验收与开发测试分别记录。 - -## 当前实现 - -- `PAYROLL_MAKER_USER_ID` 绑定现有指定账号。未配置时关闭业务写入;岗位和管理员身份不代替实际制作人。登录响应返回 `can_write_payroll`,页面同步禁用写按钮。工资台账、月结和调整单查询必须登录。 -- `payroll_months` 独立记录首次生成时间和实际制作人。月结草稿首次成功生成即锁定分配,失败事务回滚;退回审批和重新生成不解锁。 -- `payroll_inputs` 追加保存正式输入版本;`payroll_allocations` 保存逐段回款、发货、指导成本、原始参数、受益人员、分管及应付差额。预演不直接升级为工资。 -- 新增正式导入预览/执行任务,沿用 worker 和稳定源关联;源/事实/目标变化使旧预览失效。只允许追加新单据和事实版本,旧单据金额或日期变化形成冲突,不静默覆盖。 -- 正式FIFO共享已有分配内核;保留期初先冲、预收待实际发货、60%起付和平方权重,累计应付减去历史已计入应付。重算按月份顺序重建尚未生成工资的后续月份;已生成工资走当月调整。 -- 正式分管取核算时固化事实,支持同一业务员的不同业务由不同经理分管;离职承接未发部分,经理本人业务排除。新核算不消费旧任意比例/负责人余额方案,旧方案仅历史查看。 -- 调整单增加类型、原台账和业务分管快照。分配调整与通用新调整的服务层统一将月份设为生成当月,不接受客户端回写历史工资月份;旧引擎兼容测试显式启用旧月份行为。 -- 备份脚本停止按30天自动删除归档文件;本轮未执行备份清理或恢复。 - -## 新回执修订 - -详见 `客户补充回执核对_2026-10-30.md`。 - -1. 同一 T+ 发货客户名头合并平账,不按合同数量分组。正式源数据使用账套内稳定客户身份聚合,导入时自动纳入该客户截至所选月的发货/回款,保留逐次发货的人员、分管及交接依据。 -2. 指导成本固定取发货月份。资料录入完成后显式封存,后续回款或重算不改变原发货月份指导成本。历史回款月取价开关不再影响正式口径。 -3. 一正一负更正单排除绩效、跨客户回款归入原业务的示例已确认并实现;多原单金额分配与通用日期依据仍只阻塞对应特殊分支。 -4. 保证金、代收款回复“不涉及”,不新增相应计提。 -5. 第05项已由用户及后续截图澄清:审核能力保留,默认关闭。`PAYROLL_APPROVAL_ENABLED=false` 时生成工资即完成,不创建审批单、审批步骤或自动通过痕迹;需要时可显式开启原财务/领导流程,仍受各审批对象参数控制。与旧核算引擎兼容开关独立。 - -## 接口与调用 - -正式导入继续调用 `POST /api/v1/system/tplus/work-runs`: - -```json -{"kind":"BUSINESS_PREVIEW","request_key":"<本次意图的UUID>","month":"2026-03","group_keys":["<客户平账资料标识>"]} -``` - -预览完成后以 `BUSINESS_APPLY`、同次预览的 `preview_no` 和新意图UUID执行。网络重试复用同一请求键。人员、产品、客户基础导入须先完成,缺数据行保留待补。 - -人工核算准备:`POST /api/v1/payroll/businesses/{id}/input`,明确 `month`、`expected_version`、`evidence`、`opening_balance`、`history_confirmed=true`、`guidance_finalized=true`,并逐条提供 `shipment_ownerships` 中的发货明细ID、业务员、经理、含税单位指导成本。归属变动和离职交接使用版本化事实;不按当前人员直属关系推算历史。 - -正式计算:`POST /api/v1/payroll/businesses/{id}/calculate`,请求 `{"month":"2026-03"}`;重算增加非空 `reason`,返回受影响的 `recalculated_months`。页面调用见 `frontend/src/api/payroll.ts`,业务列表提供正式核算入口。 - -查询:`GET /api/v1/payroll/months/{month}`、`/businesses/{id}/input`、`/ledger/{id}/allocations`;分配调整:`POST /api/v1/payroll/allocation-adjustments`,必须关联已生成工资的原台账,月份由服务端确定。 - -## 迁移与验证 - -- V18:正式输入、分配明细、生成锁与FIFO事件唯一键。替换台账唯一索引前先建立回款外键支撑索引。 -- V19:调整类型、原台账和分管快照。模型、Alembic、迁移SQL与开发初始化同步;已有正式结果时拒绝破坏性结构回退,应回退应用版本并保留数据。 -- 集成测试入口:`python scripts/run_isolated_tests.py`;校验测试库名称、显式授权标记及真实引擎URL。运行器新建独立数据库及受限测试账号,凭据只经环境传入,不输出、不写源文件。 -- 已有本轮证据:单元746项通过;正式链路5项MySQL通过;V18空库升级/回退/再升级通过。新回执修订后的最终完整回归、V19结构、最终浏览器与构建结果待末次运行回填,不提前记为全部通过。 - -## 尚未完成的交付条件 - -真实样本仍需核实分类、成本、期初及历史已处理金额,不填默认值。当前未对原开发业务库或生产库执行迁移,未绑定实际生产制作人、未生成真实工资。SQL Server2008R2兼容、每周同步、服务托管、告警和目标环境全量/增量恢复演练仍保留后续任务。实际资金支付属于财务系统范围。 - -## 本轮最终验证证据 - -- 完整单元:749 passed,1条既有Starlette测试客户端弃用提醒,59.88秒;`.ai/formal-payroll-unit-delivery.log`。 -- 完整隔离集成基线:396 passed、1 failed,850.91秒;唯一失败是原毛利润用例的制作人夹具被参数管理员夹具覆盖。已将 writer 显式依赖 admin 保证绑定顺序,未放宽产品权限;该用例及受影响模块复测75 passed,137.32秒,`.ai/formal-payroll-latest-focused.log`。本轮不把“基线+定点”写成最新代码一次性完整回归全绿。 -- V18/V19隔离迁移:从当前head回退至07b8c9d0e1f2,再升级至19d0e1f2a3b4;结构同步9 passed,3.00秒,`.ai/formal-payroll-migration-final.log`。 -- Ruff、差异空白检查通过;前端vue-tsc与Vite生产构建通过。Vite仍有既有的大资源包体积提示,不作为功能测试失败;`.ai/formal-payroll-frontend-delivery.log`。 -- 浏览器:使用合成接口数据验证真实Vue页面的正式核算入口、资料填写及提交请求(含成本封存确认)、768宽弹窗、默认关闭审核时无提交按钮;浏览器错误0。此项为界面/请求契约检查,不冒充真实客户金额验收。 -- MySQL正式链路覆盖:默认关闭审核时工资/调整单不建ApprovalOrder或ApprovalStep;开启审核后财务和领导节点可用;指定账号写入、其他管理员拒绝、并发防重、失败不锁及成功锁定、固化分管和部门对账。 - -原开发库、T+生产连接与真实工资未被本轮测试写入。后续目标环境仍需应用迁移、绑定实际制作人、按实际资料完成样本验收。新回执的已确认更正示例已实现,通用多原单/日期规则仍按范围保留。 - -### 最新完整回归收口(优先于上方中间运行记录) - -- 最新完整集成覆盖全部29个测试文件,在两套独立库分组执行:A组215 passed(523.98秒),B组184 passed(407.76秒),共399 passed,无失败、无跳过。日志`.ai/formal-payroll-full-current-a.log`和`.ai/formal-payroll-full-current-b.log`。此前旧夹具失败已关闭,不再作为当前遗留项。 -- 完整单元749 passed;V18/V19隔离迁移往返及结构9 passed;最终类型与生产构建通过。浏览器还验证非制作人的管理员无法新增/正式核算,以及默认关闭审核时无审批列与提交按钮。 -- 当前阶段代码和自动化验证完成,真实样本金额、实际账号绑定及目标环境部署未验收,不将项目整体标为已交付。 - -### 2026-10-30 项目收尾复验 - -- 后端单元测试重新执行:`786 passed`,失败 0;仅有既有 Starlette/httpx 弃用提醒。 -- 隔离数据库完整集成重新执行:`406 passed`,失败 0、跳过 0,退出码 0;测试库由 `scripts/run_isolated_tests.py` 创建并在隔离环境中运行。 -- `ruff check app tests`、前端 `vue-tsc --noEmit`、Vite 生产构建通过;构建保留既有大资源包体积提示。 -- Windows `Test-PayrollTaskPlan.ps1` 与 `Test-PayrollHostRuntime.ps1` 通过,验证了默认禁用、单实例、重启策略、停止标记、路径空格和失败退出码传递;未注册计划任务。 -- 本次未连接生产 T+、未绑定生产制作人、未生成真实工资、未运行生产备份删除或恢复操作。外部验收条件仍按计划节点 6 保留。 - -### 第 03 项更正场景实现 - -- 新增版本化 `CORRECTION` 事实,要求记录更正配对标识;发货更正必须明确排除绩效,跨客户回款必须指定原业务标识。 -- 预演会保留更正发货源记录并输出排除明细,不进入 FIFO、销售额和正式绩效;B 客户侧的被转归回款自动排除,A 原业务侧按人工事实纳入,正式导入沿用同一输入版本和幂等保护。 -- 前端工作台已增加更正事实录入;新增 FIFO 与事实校验用例。该项已完成代码实现,真实样本仍需按客户资料做金额验收。 diff --git a/docs/系统监控运维说明.md b/docs/系统监控运维说明.md new file mode 100644 index 0000000..95879cc --- /dev/null +++ b/docs/系统监控运维说明.md @@ -0,0 +1,59 @@ +# 系统监控运维说明 + +系统管理 → 系统监控(`/system/monitor`),仅管理员可访问。部署按一个后端应用进程运行;后台采集与浏览器访问无关。 + +## 开通与采集 + +先安装 `backend/pyproject.toml`/`uv.lock` 中的依赖,新增依赖为 `psutil`。使用项目迁移流程应用 V23(`23b4c5d6e7f8`),再启动后端。V23 新增 `monitor_snapshots`、`monitor_request_minutes`、`monitor_events` 及管理员查看权限,不修改工资数据。 + +若后续迁移已接在 V23 后,完整环境按项目当前 head 部署;不要向已有库重跑初始化 SQL。生产迁移按项目审批流程执行。本轮开发验证只对独立测试库和已核实的开发环境操作。 + +- 每 15 秒采集资源、MySQL/Redis 连接和 T+ 状态,每分钟持久化资源均值及请求统计。 +- 请求线程只写有界内存缓冲,正常请求仅保留聚合指标。异常、慢请求和后台错误保留脱敏事件。 +- 监控三张新表保留 7 天,仍未恢复的健康异常保留至恢复后过期。清理每批每表最多 1000 行,不清理工资或审计记录。 +- 数据库不可写时缓冲最多十分钟、2000 条待写事件;超过容量可能产生缺口,页面显示丢弃数量。缺失时段不会按零补造。 +- 页面默认每 15 秒刷新;隐藏、关闭、离开页面或手动关闭开关时停止页面轮询,后台仍采集。 + +## 指标口径 + +- 服务器资源实际为进程可见的系统资源;容器环境未换算 cgroup 限额,不表示宿主机真实可用额度。应用进程内存为 RSS,进程 CPU 按可见 CPU 总量折算。 +- CPU 首次采样无可比基线,显示未知;后续周期才产生 CPU 使用率。 +- 近 5 分钟使用当前分钟与前四个分钟桶。4xx 单独统计,5xx 才计入系统错误率。 +- P95 使用可合并的固定耗时直方图计算近似值,不是平均值。没有请求时错误率为 0、P95 为“暂无”。 +- 接口以方法和路由模板统计,不存原始 URL、查询参数或请求正文。未知地址归入 `/__unmatched__`,超过每分钟路由上限时归入 `/__other__`。 +- 性能排行最多读取 20000 个接口分钟记录并展示 200 个接口,超过上限明确提示截断,应缩短范围或指定接口。 +- 普通业务异常、校验失败和权限拒绝不产生 5xx 告警;监控、探活及接口文档请求不参与性能统计。 + +## 异常判断与排查 + +阈值配置见 `backend/.env.example` 中 `MONITOR_*`,变更后重启生效。 + +| 异常 | 默认条件 | 首先检查 | +| --- | --- | --- | +| CPU/内存偏高 | 连续采样达到 85%,持续 5 分钟 | 同时段资源趋势、慢接口、同步任务 | +| 磁盘空间不足 | 可见数据盘使用率达到 90% | 日志增长、磁盘剩余容量及存储目录 | +| 接口错误率偏高 | 近 5 个分钟桶至少 20 次请求,5xx 比例达到 5% | 失败接口排行与异常请求编号 | +| MySQL/Redis 不可用 | 有限超时的连接探测失败 | 服务状态、网络、配置变量,不向页面复制凭据 | +| T+ 健康异常 | 复用既有心跳、15 分钟排队、8 天成功采集等规则 | 关联批次、采集进程和原 T+ 页面 | + +总览 → 异常时段 → 接口性能 → 查看异常 → 诊断事件详情,可以复制 `request_id`。对应 HTTP 响应头为 `X-Request-ID`,服务端日志中为 `request_id=...`。同一次请求异常只记录一条请求事件;健康类事件按错误码合并,记录首次、最近、持续采样次数及恢复时间。 + +运行事件页可按事件类型、完整路由模板和请求编号筛选。曲线点击可切换到该时段的事件;历史截止时间使用北京时间。诊断摘要下载只包含当前运行概况和所选条件下当前页事件,不包含完整日志、堆栈、请求参数、SQL 参数、薪资明细或连接配置。 + +后台运行错误仅记录固定摘要,完整原因保留在受控服务端日志。T+ 任务相关错误仍以原批次记录为依据,本页不新增任务创建、重试或停止操作。 + +## 故障边界 + +- MySQL/Redis 同时也是现有鉴权依赖。它们异常时监控接口可能无法访问,页面保留最后成功数据并标记连接失败;不绕过鉴权。 +- 超过 45 秒未采集,当前状态显示未知。资源采集失败、无历史数据、未配置 T+ 与正常状态分别展示。 +- 未配置、主动停用 T+ 不表示宕机;任务状态读取失败不把已有异常自动标记为恢复。 +- 应用或服务器完全停止后,站内页面无法主动告警。外部探测、消息通知和多实例集中采集属于后续扩展。 +- 应用回滚可保留 V23 新表。有历史监控数据时 V23 降级拒绝删除表,需保留数据并回退应用版本。 + +## 接口与验证 + +管理员接口前缀 `/api/v1/system/monitor`:`GET /overview`、`/trends`、`/interfaces`、`/events`、`/events/{id}`、`/diagnostic`。列表与普通查询沿用统一响应格式,诊断下载为 JSON 附件。现有 `/api/health` 契约保持不变。 + +单元测试:`python -m pytest tests/unit/test_monitoring.py tests/unit/test_monitor_service.py -q`。 + +浏览器合成场景:项目根执行 `node frontend/e2e/monitor.mjs`,可通过 `PLAYWRIGHT_MODULE`、`MONITOR_UI_URL` 和 `MONITOR_UI_OUTPUT` 指定已安装的 Playwright、前端地址及输出目录;不会登录真实账号或写入业务数据。 diff --git a/docs/绩效核算业务确认单_2026-10-30(2).xlsx b/docs/绩效核算业务确认单_2026-10-30(2).xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f9ede2850c21f8ac8be407843e4717b93d015c87 GIT binary patch literal 12704 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 rZK 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 literal 0 HcmV?d00001 diff --git a/docs/角色授权使用说明.md b/docs/角色授权使用说明.md new file mode 100644 index 0000000..72a03fa --- /dev/null +++ b/docs/角色授权使用说明.md @@ -0,0 +1,42 @@ +# 角色授权使用说明 + +## 操作顺序 + +1. 在「系统管理 → 角色管理」创建角色,例如“财务经办”“业务录入”“只读查询”。 +2. 点击角色的「配置权限」,按业务分组找到模块,勾选需要的操作并填写修改原因。 +3. 在「用户管理 → 分配角色」选择一个或多个角色,查看自动继承的权限,保存分配。 + +多个角色的权限取并集。角色权限变更会即时影响全部绑定用户,停用角色会撤销其带来的权限。角色名称不决定权限,勾选的操作才是实际授权依据。 + +## 新权限面板 + +- 左侧为业务分组和已选/总权限数量,右侧每个模块只出现一次,操作横向排列。 +- 模块全选支持半选状态;勾选操作会自动包含查看权限,取消查看会同时取消该模块的操作。 +- 搜索支持模块和操作名,搜索后显示相应模块;模块全选始终作用于完整模块。 +- 可以从已有角色复制权限,再调整保存;复制管理员时不会复制管理员专用权限给普通角色。 +- 保存前显示新增、撤销数量,修改原因和保存操作固定在底部。 +- 系统管理员为内置固定全权限,仅供查看,不显示可编辑的勾选项和保存按钮。 +- 用户侧只分配角色,继承权限仅供查看,不再提供“额外允许/明确禁止”等重复授权入口。 +- 预览失败时禁止保存;授权版本冲突时需要重新加载;关闭有未保存改动的面板会提示放弃或继续编辑。 + +## 工资经办与计提岗位 + +已取消全局唯一工资制作人绑定和「权限与工资制作人」菜单。旧地址 `/system/authorization` 跳转角色管理。 + +“工资经办”是一个可配置的普通系统角色,可以分配给多个实际经办账号。具有核算、工资生成或调整权限的账号可执行对应操作,不需要再指定一次账号。查看权限不会自动变成写权限;生成工资、核算、调整等操作分别校验相应权限。 + +每个月实际制作人的账号与用户名仍自动记录。已生成工资的月份锁定继续生效,不能因更换角色、管理员身份或取消全局绑定而绕过。差额仍按既有调整规则处理,历史工资和操作留痕保留。 + +原「岗位角色」改名为「计提岗位」,用于人员岗位、计提公式和参数,不决定登录账号能访问哪些页面。 + +## 迁移与兼容 + +V26(`26e7f8a9b0c1`)保留旧表和历史记录,停用旧授权入口权限,清空旧全局制作人引用,更新默认工资角色名称及说明。自定义的角色名称不覆盖。角色与用户的现有绑定和权限项不会批量重置。 + +若 `user_permission_overrides` 存在记录,迁移会在修改前拒绝执行,需要先整理为等效角色,避免隐式改变用户权限。当前开发环境已核实该表为 0 条。 + +旧用户授权 API 继续接受空的 `overrides: []`,非空覆盖返回参数错误。旧制作人设置读取返回 `mode: roles`,写入明确提示改用角色授权,不再修改角色或绑定账号。 + +回退 V26 只恢复旧入口,不推测绑定哪个账号;旧版本需要管理员核对后重新指定。生产迁移与回退仍遵循项目操作审批。 + +本地开发库已完成 V26 核验。备份 SHA-256 为 `ed473db828140a2d64592f7b781d6a780d0015d38386f93fea15bc5d549883f1`。迁移后仍有并行账号与角色验收数据变化,未自动清理;这些数据不属于 V26 的变更内容。生产库仍未操作。 diff --git a/docs/需求补齐实施与验收记录_2026-11-02.md b/docs/需求补齐实施与验收记录_2026-11-02.md new file mode 100644 index 0000000..a721dc4 --- /dev/null +++ b/docs/需求补齐实施与验收记录_2026-11-02.md @@ -0,0 +1,95 @@ +# 需求补齐实施与验收记录 + +日期:2026 年 11 月 2 日。对应用户批准的《需求缺口补齐与文档修订计划》及“模块需要的页面功能一定不要少”的要求。 + +本次交付覆盖原需规全部 16 个功能小节的页面对照,补齐 F01—F07。实现、自动化验证、真实客户金额验收和生产启用分别记录,不以修改文档代替实现。 + +## 需求基线与文件 + +- 原始文档:`衍水绩效管理系统功能需规.docx`,保留不修改。SHA-256:`ad6d6a4b38bae74c156cee065bbf60b2e7f95298d8b5f31297b56933f1504c92`。 +- 修订文档:[衍水绩效管理系统功能需规_修订版_2026-11-02.docx](衍水绩效管理系统功能需规_修订版_2026-11-02.docx)。保留 2.1—2.5 全部 16 小节,更新后续已确认口径,新增变更与验收章节。 +- 本次计划:`tasks/需求补齐计划_2026-11-02.md`。已有部署、权限和监控计划及未提交修改保留。 +- 版本依据:2026.9.8 修改方案、2026-10-30 已归档回复,以及本轮用户对系数表、试用期年度范围和产品来源含义的选择。 + +## 七项缺口的实现与页面验收 + +| 编号 | 需求位置 | 本次实现 | 页面操作及主要实现位置 | +|---|---|---|---| +| F01 | 2.1.2、2.3.1、2.3.3 | 企业户按产品类别和到账日取比例;保留默认兜底及历史日期版本;混合产品逐行计算 | 计提参数/绩效系数表维护分类比例,计算预览、正式核算和台账明细使用同源规则。`rate_rules.py`、`tplus/calculation_preview.py`、`tplus/fifo.py` | +| F02 | 2.3.3、后续信息员方案 | 信息员用销售额乘岗位比例,默认 1‰,不再套用折算毛利基数;规则、基数、参数及快照指纹进入逐段结果 | 岗位角色、计提参数、试算与正式台账保持一致。销售额 10000 元、比例 1‰ 的业务回归为 10 元 | +| F03 | 2.1.1、2.3.3、2.4.1 | 基本工资按人每月只算一次,无绩效在职人员可发薪;试用期及任职日期/工资标准按生效版本保存;缓发、年度门槛、跨年续付、扣回及待审核占用分列 | 人员页新增日期和生效记录;月结页增加缓发与结清预览、人员/年度筛选、原台账明细、当月调整及导出;月结详情、部门报表和 Excel 展示基本工资/正常绩效/缓发/年度补发。`probation_service.py`、`salary_completion.py`、`personnel_salary.py` | +| F04 | 2.2.1、2.2.4 | 含税单位指导成本乘数量得到总成本,按分舍入;同时提交不一致金额拒绝;历史仅成本额记录兼容;正式已封存成本受保护 | 业务明细与毛利润视图联动;正式资料保留按发货月份封存。`cost_rules.py`、业务入参及业务服务 | +| F05 | 2.1.2 | 从已采集的有效正向发货选最新数量和含税成交价,保留日期/单号;人工调整优先,允许恢复源值;不导入 T+ 成本作绩效成本 | 产品页显示最近发货数量、最近成交价、来源和人工保护状态,提供恢复源值确认。`product_completion.py`、`tplus/master_import.py`、产品服务 | +| F06 | 2.1.2 | 业务明细选择、预览、名称规格去重、单位/类别冲突处理、确认执行及结果;重复提取不重复建档;只建立关联,不改历史金额 | 产品页“从业务提取产品”弹窗提供查询、分页、勾选、预览、执行和逐项冲突。`ProductExtractDialog.vue` 及产品提取接口 | +| F07 | 2.3.1、2.5.2 | 完整分类/户型/阶段表格;首日、线性斜率、截止天数、超期及企业户固定比例可维护;系统系数和 360 天平均系数由公式生成;同一参数版本源 | 参数页新增绩效系数表、日期查询、维护弹窗、模板/导出、Excel 导入预览/确认、逐行错误、版本历史与对比。`CoefficientPanel.vue`、`coefficient_service.py`、系数表接口 | + +### 全部模块的页面能力对照 + +| 原小节 | 页面与入口 | 保留及补齐的操作 | +|---|---|---| +| 2.1.1 | 基础数据→人员管理 | 新增、详情、编辑、查询、删除保护、在职/离职与生效日、工资标准和任职版本、试用/转正日期、区域及拓展计划 | +| 2.1.2 | 基础数据→产品管理 | 名称规格查询、类别/状态筛选、新增、详情、编辑、启停、删除保护、来源及人工保护、恢复源值、业务提取预览/执行 | +| 2.1.3 | 基础数据→客户管理 | 档案增删改查、三种客户类型、归属维护和历史、评级入口 | +| 2.2.1 | 业务数据→业务管理;T+ 正式导入;正式核算弹窗 | 业务编号、产品明细和指导成本、负责/协助归属、状态和时间线、特殊业务、资料封存、正式核算及重算 | +| 2.2.2 | 业务数据→发货管理 | 新增、详情、编辑、查询、业务及批次关联、产品明细、日期、金额和运费 | +| 2.2.3 | 业务数据→回款管理 | 新增、详情、查询、编辑和删除保护、回款批次、到账日期及金额、核算状态 | +| 2.2.4 | 业务详情→毛利润视图;正式核算资料 | 指导单位成本和成本额校验、行级毛利、分类汇总、阈值、缺成本提示、封存保护 | +| 2.2.5 | 客户管理→评级计算器 | 五项手工评分、总分/等级、等级映射新增/编辑/删除、保存总评分 | +| 2.3.1 | 系统管理→计提参数/绩效系数表 | 参数和阶段维护、生效日、二次确认、试算、历史/比较、Excel 模板/导入预览/确认/导出 | +| 2.3.2 | 发货/回款详情、计算预览、台账逐段明细 | 首日计数、跨年天数、预收日期、实际 FIFO 匹配段 | +| 2.3.3 | 正式核算、核算台账、月度结算、工资调整 | 起付和 R²、逐段依据、防重和重算;按人基本工资、缓发、年终及续付预览、当月调整、月结锁和工资分项导出 | +| 2.4.1 | 个人绩效明细、部门绩效汇总 | 人员/月份等查询、计提比例与 R、团队和公司分成、成员明细、冻结工资分项及对账依据 | +| 2.4.2 | 业务统计、回款统计 | 业务查询、区间/户型/产品统计、分类比较及下钻 | +| 2.4.3 | 各报表、打印页、工资/缓发导出 | Excel、筛选和签字稿、浏览器打印/另存 PDF、工资分项及缓发原台账导出 | +| 2.5.1 | 用户、角色及权限、日志 | 账号增删改查、改密、启停、角色权限及操作人员记录、登录/操作/参数日志 | +| 2.5.2 | 公司信息、岗位角色、计提参数/系数表 | 公司名称和 logo、岗位模板、参数版本及完整系数表维护和导入导出 | + +## 接口及数据兼容 + +- 系数表:`GET/PUT /api/v1/system/coefficients`,`GET /export`,`POST /import-preview`。导入只预览,确认通过 PUT 写同一参数版本;文件保留基准日期,派生列不一致时整批拒绝。 +- 产品提取:`GET /api/v1/base/products/extract/candidates`、`POST /extract/preview`、`POST /extract`;来源恢复:`POST /api/v1/base/products/{id}/restore-source`。 +- 缓发及结清:`GET /api/v1/payroll/probation`、`GET /probation/export`、`POST /probation/adjustments`;工资分项:`GET /api/v1/payroll/salary-export/{month}`。 +- 新接口接入现有操作权限,不凭前端按钮判定授权;Excel 上传在统一权限中间件中按表单类型处理,避免重复消费请求流。 +- V24 增量结构:试用期缓发及结清两表,人员任职/工资历史、产品来源和人工保护、工资分项列,以及五个分产品个人户系数参数。迁移 SQL、ORM 和开发初始化同步;结构定义固定,回退遇到新业务数据拒绝删除。 +- 当前工作区的 V25/V26 分别为系统监控权限兼容及角色授权归一迁移,保留其原工作;本次功能使用现有角色权限,不重建已停用的全局制作人/个人覆盖入口,实际工资操作人员仍保留在快照和操作日志中。 +- 历史已生成工资不自动重算。人员当前状态不能改变旧台账试用期分类;源导入不覆盖人工核算分类和已封存指导成本;重复导入和提取保留幂等/冲突检查。 + +## 金额、历史及并发验证要点 + +- 市政 2‰、轨交 5‰、默认 3‰ 的分类解析;信息员销售 10000 元为 10 元。 +- 数量 10、单位指导成本 50,成本额为 500;成本冲突拒绝,缺成本和历史成本兼容。 +- 试用期计提 20000、门槛 18000,若符合支付条件仅 1000,则年底补 1000;后续符合条件增至 3000 时再补 1000;权益降低可形成负向差额。 +- 待审核结清与已支付分开,驳回/撤回释放占用;无效后续记录不阻塞较早月份,人员锁与审批锁顺序一致。 +- 人员工资标准、岗位、离职/在职变更按生效日期留存;JSON 历史追加前锁人员,避免并发丢版本;工资基本额每人只计一次。 +- 系数页和普通参数页提交使用同一串行化入口,指纹包含未来版本;过期预览不能静默覆盖另一笔预约变更。 +- 最新有效发货按日期/单据/明细稳定排序,红冲和无效单据排除;人工产品值保护;单位/分类冲突不静默覆盖。 + +## 本轮验证记录 + +| 检查 | 结果/证据 | +|---|---| +| 新增金额、历史、产品与工作簿专项单元 | 11 项通过,包含分界天数小数原文及预收/经理排除优先级;`backend/tests/unit/test_requirement_completion.py` | +| 完整单元 | 最后完整执行 `899 passed`,失败 0;保留一条既有 Starlette/httpx 弃用提醒,见 `.ai/requirements-unit-final.log` | +| 隔离 MySQL 聚焦验证 | 产品、人员、参数、正式工资、月结、报表和结构已验证;参数专项 24 项、授权/正式工资专项 19 项、年度续付完整接口 5 项通过;重复调用和已生成工资保护均有断言 | +| 真实浏览器与实际 API | 完成系数编辑、下载/上传/确认、业务提取、恢复来源、缓发明细、真实月结、详情及 Excel 下载、部门工资分项打印;9 组检查全部通过,检查结果见 `.ai/requirements-browser-result.json`,页面异常和 API 失败均为 0 | +| 响应式 | 1440、768、390 宽度检查;截图 `.ai/requirements-coefficients-*.png`、`requirements-salary-1440.png`、`requirements-extraction-1440.png` | +| 前端类型与生产构建 | 已通过;保留既有大资源包提示,见 `.ai/requirements-frontend-build.log` | +| Ruff | `app tests` 通过;`.ai/requirements-ruff-final.log` | +| 迁移往返及完整集成 | 空隔离库升级→回退至 V17→再升级通过(首轮日志);最后按全部 32 个文件分组执行,A 组 `211 passed`、B 组 `213 passed`,均退出码 0;新增年度续付场景所在文件再复测 `5 passed`。日志为 `.ai/requirements-integration-final-A.log`、`requirements-integration-final-B.log`、`requirements-yearend-final.log`,重复测试不累加为独立用例数 | +| Word 排版 | 渲染为 5 页,已查看整稿缩略图及变更表整页;保留原 16 小节,无拆开的变更表;中间 PDF 和图片仅用于内部 QA | + +本轮集成回归覆盖快照为 32 个文件;并行工作区后续新增的 T+ 同步控制台测试不计入本次 424 项分组数字,也不将本次结果声称为其他任务新增代码的验收。两组文件清单保存在 `.ai/requirements-regression-manifest.json`。 + +本轮完整集成中发现的过期权限期望、旧经理试算拒绝期望和旧预收拒绝期望,按当前已确认功能改为相应金额/权限断言;没有删除失败用例或关闭检查。历史月份参数测试固定业务日期,不依赖实际今天。 + +## 尚需真实资料或目标环境的验收 + +- 真实客户指导成本、期初及历史已处理金额齐备后,逐笔及整月工资与人工结果核对。 +- 客户目标 SQL Server 2008 R2、正式源读取、服务托管、备份恢复及生产启用另行验收。 +- 通用多原单金额分配与任意日期更正规则仍按既有待确认边界处理,不猜规则。 + +本轮使用的浏览器和金额数据为隔离合成样本,不替代上述真实业务验收;没有提交、推送或启用生产连接。 + +## 本次完成状态 + +F01—F07 已完成页面、接口、存储、计算和本地验证,修订版保留原 16 个小节;原文哈希复核未变,Word 已渲染 5 页并目视检查。辅助脚本、日志和截图留在已忽略的 `.ai/`,未纳入版本管理。当前结论为“本次需求补齐的开发及本地验收完成”,不扩大为真实客户工资对账、其他并行任务或生产部署全部完成。 diff --git a/docs/需求补齐流程测试报告_2026-11-02.md b/docs/需求补齐流程测试报告_2026-11-02.md new file mode 100644 index 0000000..a335aa5 --- /dev/null +++ b/docs/需求补齐流程测试报告_2026-11-02.md @@ -0,0 +1,105 @@ +# 需求补齐流程测试报告(2026-11-02) + +## 结论 + +本轮已完成隔离数据库端到端回归。后端单元测试 922 项全部通过;隔离集成测试 A 组 315 项全部通过,B 组 122 个唯一用例在修复开发库结构同步后全部通过:首轮 119 通过、3 项结构同步失败;修复后复跑 3 个失败点及其结构回归,专项 10 项全部通过;前端类型检查和构建通过;Ruff 针对本轮修改范围检查通过。此前浏览器流程检查记录了 9 项检查、0 项失败。 + +本轮在回归中发现并修复了三个交付前问题:V28 迁移把“注释 + CREATE TABLE”整段误判为纯注释导致新库缺表;`db/init/init-dev.sql` 缺少 `calc_template_definitions`,且版本号仍停在 V27;新公式模板接口缺少权限映射。以上问题已修复并复测,未发现遗留失败。 + +## 测试范围与证据 + +| 范围 | 结果 | 证据 | +| --- | ---: | --- | +| 后端单元测试 | 922 passed / 0 failed | `.ai/unit-regression-final-20261102.log` | +| 隔离集成 A 组 | 315 passed / 0 failed | `.ai/e2e-flow-groupA.log` | +| 隔离集成 B 组 | 119 passed,3 项结构同步失败;修复后专项 10 passed / 0 failed | `.ai/e2e-flow-groupB.log`、`.ai/e2e-schema-fix-regression.log` | +| 审批专项回归 | 24 passed / 0 failed | `.ai/approval-regression-20261102.log` | +| 前端类型检查 + 构建 | 通过 | `.ai/frontend-build-20261102.log` | +| Ruff | 修改范围全部通过 | 命令:`ruff check app tests alembic/versions/28a9b0c1d2e3_calc_template_definitions.py` | +| 浏览器流程检查 | 9 项检查,0 项失败 | `.ai/requirements-browser-result.json` | + +## 需求覆盖矩阵 + +| 需求小节 | 功能模块 | 主要测试文件 | 结论 | +| --- | --- | --- | --- | +| 2.1.1 | 人员管理 | `test_personnel.py` | 通过 | +| 2.1.2 | 产品管理、T+ 同步、提取与调整 | `test_products.py`、`test_requirement_completion.py` | 通过 | +| 2.1.3 | 客户管理、归属、评级入口 | `test_customers.py`、`test_ratings.py` | 通过 | +| 2.2.1 | 业务创建、明细、指导成本、状态流转 | `test_businesses.py`、`test_formal_payroll.py` | 通过 | +| 2.2.2 | 发货登记、明细、FIFO 与归属 | `test_shipments.py`、`test_formal_payroll.py` | 通过 | +| 2.2.3 | 回款登记、批次、到账与 FIFO | `test_receipts.py`、`test_formal_payroll.py` | 通过 | +| 2.2.4 | 指导价、毛利润与成本封存 | `test_businesses.py`、`test_formal_payroll.py` | 通过 | +| 2.2.5 | 客户评级计算器 | `test_ratings.py` | 通过 | +| 2.3.1 | 参数、系数、公式模板 | `test_param_management.py`、`test_requirement_completion.py`、公式模板权限测试 | 通过 | +| 2.3.2 | 回款天数、跨年、首日计数 | `test_receipts.py`、`test_formal_payroll.py` | 通过 | +| 2.3.3 | 绩效计算、试用期缓发、工资闭环 | `test_formal_payroll.py`、`test_settlements.py`、`test_requirement_completion.py` | 通过 | +| 2.4.1—2.4.3 | 明细、部门、业务、回款报表及导出 | `test_reports.py` | 通过 | +| 2.5.1 | 用户、角色、授权、审批权限与日志 | `test_user_management.py`、`test_role_management.py`、`test_authorization.py`、`test_log_query.py` | 通过 | +| 2.5.2 | 公司信息、系统设置、监控 | `test_settings.py`、`test_tplus_automation.py`、`test_tplus_workbench.py` | 通过 | +| 补充规则 | 二次分配与审核链 | `test_approval_flow.py`、`test_secondary_allocation.py`、`test_approval_version.py`、`test_formal_payroll.py` | 通过 | + +## 核心业务链路验证 + +`test_formal_payroll.py::formal_chain` 先建立在职业务员和营销经理,再创建客户与含数量、销售单价、指导成本的业务;随后登记发货、回款,提交期初、历史处理金额、发货归属、分管经理和指导成本封存,最后执行正式核算并生成月结。该夹具把用户要求的主链路串成同一事务化测试样本:业务创建 → 发货登记 → 回款登记 → 指导价/成本 → 正式绩效 → 工资结算。 + +| 链路节点 | 验证内容 | 主要证据 | +| --- | --- | --- | +| 业务创建 | 编号、客户、产品明细、指导成本、状态和特殊标记 | `test_businesses.py`、`formal_chain` | +| 发货登记 | 发货日期、明细金额、运费、业务关联和归属数据 | `test_shipments.py`、`formal_chain` | +| 回款登记 | 回款日期、金额、批次、FIFO 和核销防重 | `test_receipts.py`、`test_formal_payroll.py` | +| 指导价与毛利润 | 单位成本换算、封存、毛利润和折算基数 | `test_businesses.py`、`test_formal_payroll.py` | +| 客户评级 | 五项评分、总分、等级映射和保存 | `test_ratings.py` | +| 绩效计算 | 天数、分类比例、R²、起付、信息员、企业户、预付和重算 | `test_calc.py`、`test_formal_payroll.py` | +| 工资发放 | 月结快照、基本工资、绩效、缓发、年终补发、审批开关、锁定和导出 | `test_settlements.py`、`test_formal_payroll.py`、浏览器月结检查 | + +## 补齐功能 F01—F07 核对 + +| 编号 | 结果 | 关键行为与证据 | +| --- | --- | --- | +| F01 企业户分类比例 | 通过 | 市政、轨交、默认兜底和历史到账日期版本由参数、预演、正式核算共用;混合产品逐行计算。证据:`test_param_management.py`、`test_requirement_completion.py`、`test_formal_payroll.py` | +| F02 信息员计提 | 通过 | 销售额 × 岗位比例,10000 元 × 1‰ 的回归断言为 10 元;不再用折算毛利作为基数。证据:`test_requirement_completion.py`、单元和集成参数样例 | +| F03 基本工资与试用期 | 通过 | 无绩效在职人员可生成基本工资;试用期绩效缓发;18000 元边界、跨年续付、转正、负向调整、重复生成和审核占用均有断言。证据:`test_formal_payroll.py`、`test_settlements.py`、`test_requirement_completion.py` | +| F04 指导成本联动 | 通过 | 数量 10 × 含税单位指导成本 50 = 成本额 500;同提金额不一致拒绝;封存后不可编辑覆盖;历史总成本兼容。证据:`test_businesses.py`、`test_formal_payroll.py`、`test_requirement_completion.py` | +| F05 产品来源同步 | 通过 | 最新有效正向发货按单据日期、单据 ID、明细 ID 排序;展示来源日期和单据;人工值保护与恢复源值有测试。证据:`test_products.py`、`test_requirement_completion.py` | +| F06 业务提取产品 | 通过 | 明细选择、提取预览、确认执行、同名同规格、单位/分类冲突、重复提取幂等和仅建立关联均验证。证据:`test_products.py`、`test_requirement_completion.py`;浏览器检查包含选择、预览、执行和结果展示 | +| F07 完整系数表 | 通过 | 分类、户型、阶段、日期版本、模板下载、导入预览/确认、导出、历史比较和正式计算消费均验证;公式模板权限补齐后通过。证据:`test_param_management.py`、`test_authorization_policy.py`、浏览器系数页 9 项检查 | + +## 页面功能与权限核验 + +真实浏览器检查覆盖系数表编辑和二次确认、模板下载、真实上传预览及导入确认、业务提取、恢复来源、年度结清预览、真实接口月结、工资分项与 Excel 下载、部门打印页,以及 1440/768/390 宽度检查。后端权限回归覆盖全部业务路由的权限映射、未登记接口默认拒绝、按钮权限对应的服务端校验、审批节点权限和公式模板接口权限。 + +页面清单与七项补齐功能的逐项实现位置另见 [需求补齐实施与验收记录_2026-11-02.md](需求补齐实施与验收记录_2026-11-02.md)。该记录保留原需规 16 个小节的页面对照,本轮测试报告不降低其功能范围。 + +## 二次分配与审核链结论 + +当前口径不是继续把业务表比例方案作为新核算入口,而是保留历史比例方案供追溯;正式核算按发货归属逐笔分配。工资生成后分配锁定,差额走生成当月调整单,并保留原月结结果。 + +审核能力保留但默认关闭。关闭时工资生成直接完成,不创建审批单、审批步骤或自动通过痕迹;开启后可走财务复核、领导审核两级链路。审批内容使用提交时快照,版本号递增、重提不覆盖旧记录;任一节点驳回即整体驳回,驳回意见必填并留痕。 + +集成验证覆盖了开关关闭、开关开启、财务通过、领导通过、财务或领导驳回、驳回缺意见拒绝、节点权限、重复操作拒绝、重提撤回、快照固化、内容未变不重提、金额变化重提、方案版本化、驳回释放生效方案、正式核算无痕迹、分配调整无痕迹,以及可选审核开启后的月结两级审批。 + +## 修复与结构同步 + +- `backend/alembic/versions/28a9b0c1d2e3_calc_template_definitions.py`:迁移脚本改为逐条剥离注释行后再执行,避免新库跳过建表。 +- `db/init/init-dev.sql`:补齐公式模板表、五个系统模板种子,版本号更新为 `28a9b0c1d2e3`。 +- `backend/app/services/authorization_policy.py`:公式模板接口映射到 `system:params` 查看与更新权限。 +- `backend/tests/unit/test_models.py`:ORM 表集合加入 `calc_template_definitions`。 +- `backend/tests/integration/test_tplus_sync_console.py`:迁移往返断言版本更新为当前 head。 + +## 完成度审计 + +- 原 16 个需求小节:报告矩阵逐节登记,且均有关联集成测试;未按已有代码缩小为“仅核心模块”。 +- 七项补齐功能:F01—F07 逐项登记页面、接口、存储、计算和本地验证结果。 +- 主业务链路:业务、发货、回款、指导成本、评级、绩效、工资链路均有独立测试,并通过 `formal_chain` 形成连续样例。 +- 页面要求:浏览器检查覆盖新增高风险页面动作和响应式检查;实施记录保留全部页面对照。 +- 审核与权限:审批开关、节点权限、快照、版本、驳回、无痕迹模式和公式模板权限均有断言。 +- 本地交付门:单元、隔离集成、Ruff、前端类型检查、构建和浏览器检查均通过。 + +测试数据为隔离合成样本:人员、客户、业务、发货、回款、指导成本、分类比例、试用期额度、审批开关和报表月份均由测试代码构造,不污染共享库;数据构造见 `backend/tests/integration/factories.py`、`test_formal_payroll.py`、`test_requirement_completion.py` 及浏览器检查脚本。 + +## 边界与遗留 + +本轮使用隔离合成样本验证功能与计算链路,不替代真实客户金额、SQL Server 2008 R2、托管部署、备份恢复和生产启用验收。生产迁移、提交、推送均未执行。真实样本中的分类比例、指导成本、历史发货归属和整月工资核对仍需按实施与验收记录单独完成。 + + + diff --git a/docs/需求规格说明书.docx b/docs/需求规格说明书.docx deleted file mode 100644 index 175574b61d11ab8125d48274eb643779aebf38b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82429 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

Sazg1 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 ~JZ7x~Cbf@Kg zJ*K_5iQEjU-UaDP^Z57W_EqiOk7OHfBI`KnJi@6eZ&W(W?zXr$stpJ=aaXVvx)}7m zvlz?0FoircKspyp;2)&cvMbwLv7Yp=)qYey{cb>b^(B#YvW6ue(n(Ac8mAX#bDiPz$cJ@^k8uV|ej zy(x_#y}WC&ZukNP-UL}p&v3e0%|Nmn<~hHbqJ^1-z088lM-ICK`cB*5=9kwR8hvV&AAn2J%n~G4)Nz8mZ3a?l^}zD& z>J;w8#$E@hM1%tnButY&{hYU0X+Z<#H#BJ@ao$-5E)~zFg1L2umP^`!f6G$T0pB|_ zLrf=3(^G(M(bxsuX9Anp$Oy;^3BjpMUM04zEQP?S*Vv{3sysevfN$mqH~c*6bra_=a&b-V-22n>uO1Z1z`W2>$_}U-5({SBK8VVYupo$z z=v;0Yc=A-BT+OQMF{i@}Hd!`8*8e^UW+*9Gz*mBr!wY%UhOcCXu?c(NwmdDZvL>2* z0n6q9%bxWTImdc;^T!ssi5M_kZ2~K9Ygx#~fdP#~X3W&n!0+bz>x5R2p$KR?&O}tR z09z&JPyjURWdhQ-{S4SD2Zpksi6oPS0bQ=ml>%m338g^OE+(ar75Mg4HYH(DJv1a_ g>P 2026-11-02 规则来源更新:先读 `docs/业务规则时间线与当前口径_2026-11-02.md`。客户第 03 项已按第二版具体场景及聊天接受方案确认;旧“讨论后答复”已被后续内容补齐。内部实现与验证、实际资料及部署验收分别跟踪,不将泛化多原单分摊或任意日期覆盖列为当前客户前置条件。 -1. 将本轮 T+ 同步管理成果按迁移、后端服务、前端页面、文档拆分为规范提交;合入前本地构建与测试通过。 +依据本轮批准的 T1~T6 实施;下方正式工资及历史计划保留,当前状态以本节和开发记录为准。 -### P0.5 评审收口(本轮) +1. T1 已形成恢复库只读样本核对包,源单据、有效凭证、工号、候选期初与费用证据可追溯;2017 年初始化不直接当 2026 年切换余额。 +2. T2/T3 已实现每周九类原始采集、同周防重、手动协调、停机补最近一周、5/15 分钟最多两次明确断连重试、独立心跳和站内提示;生产自动化默认关闭。 +3. T4 已交付 Windows 计划托管包、预演、账号/ACL 校验、检查及停用;本机隔离进程验证通过,客户账号、实际注册、开机及三次恢复留待专用目标环境验收。 +4. T5 保持待资料:用户明确没有该样本人工指导成本;不替换为源成本或零成本,不重复索要同一资料。分类、费用、期初/历史及分管只核对本组,普通运维开发继续。 +5. T6 已完成 784 项单元、405 项完整隔离集成、V21 迁移往返及 16 项专项、Ruff、类型构建及合成接口真实浏览器验证。自动化开发、真实金额验收和生产启用分别记录。 -- 兼容性脚本复用应用的连接文件校验与 SQLAlchemy URL,消除手工连接串拼接;应用 URL 已有方言转义,不重复造一套转义器。 -- 默认启用加密;隔离开发环境仅允许显式回退并记录原因,不自动降级、不代填私有配置。真实旧版 TLS 兼容留待 A3。 -- 补齐 `docs/T+本地恢复与同步开发手册.md`,区分容器恢复脚本与 Windows 来宾恢复步骤。 -- 确认表新增 S1:用户已同意当前开发阶段暂不单独加密或掩码,生产保护、保留期与备份访问范围仍待统一确认;本轮不改敏感数据。 -- 定点验证连接特殊字符、默认 TLS、显式回退、错误脱敏和备份源版本判定,再在隔离 MySQL/Redis 执行完整回归。通过后分代码与文档提交推送。 +当前迁移 head 为 `21f2a3b4c5d6`,新增 V20/V21,不重写已应用迁移;仅隔离库执行。操作说明:`scripts/windows/README.md`;详细证据:`docs/同步运维自动化与样本核对开发记录_2026-10-30.md`。 -本轮验证结果:19 项定点、1001 项完整回归与 Ruff 通过;临时测试容器及卷已清理。确认表保留原业务答复与引文,环境材料与 S1 已更新;D1/D2 为设计交付,实际托管和告警未启用。 +后续跟踪已确认更正场景的配对/排除校验、前端选择及完整流程验证,以及 2008 R2 实机、目标环境恢复链及生产安装启用。通用多原单自动分摊和任意日期覆盖不作为当前客户待答复任务;未来实际出现未覆盖场景时再核实。既有节点 5 实现记录不替代当前缺口验证,未完成事项不因历史测试通过而勾选完成。 -### 轨道 A:同版本验收环境(外部依赖:安装介质) +--- -- A1 先行细化 `docs/SQLServer2008R2测试环境.md`:装机步骤、恢复步骤,以及驱动、只读权限、六类查询、中文/日期/金额、断连超时、重复同步的验收清单。 -- A2 取得合法介质后,在 `D:\work\app\tplus-vm` 完成备份源 10.50.1600 环境安装;当前不是已完成状态。 -- A3 恢复原始备份并执行完整验收,产出报告,关闭同版本兼容 PENDING 状态。 +## 前一阶段计划与证据(保留) -### 轨道 B:业务口径确认(外部依赖:客户填写) +# 当前计划:正式工资闭环与项目收尾(2026-10-30) -- B1 后续发送当前客户版:客户在 F 列填写业务答复,IT/服务商补充 E01–E03 的资料;同一例单可复用,已确认规则不重复提问。 -- B2 跟进客户群对经理个人户的反馈,回填 L6。 -- B3 答复回收后更新字段映射文档与暂定口径记录:二次分配三项(L3–L5)追认、三级角色职权(L7)在页面验收时核对。 +## 本次分节点执行计划与状态 -任务 B1–B3 是工作编号;当前客户版使用 B01/T01/E01 等编号,C1 中的旧编号仅供追溯。发送确认单是后续人工事项,本轮不代发消息。 +### 节点 1:基线与范围确认(已完成) -### 轨道 C:T+ 数据导入开发(依赖轨道 B 闭环;设计可先行) +- [x] 接续既有 `tasks/plan.md`、`tasks/todo.md` 和 `.ai/` 上下文,不覆盖未完成计划。 +- [x] 核对当前代码、迁移、测试与部署脚本,区分仓库内可完成项和必须依赖客户/目标环境的验收项。 -- C1 先行起草「staging → 业务表写入」设计:表映射、金额精度(金额用 Decimal、比例和日斜率用 Fraction)、幂等与重算授权留痕、人工字段保护(回款/发货批次由系统人工指定,业务归属变更不回溯历史)、事务边界;明确标注等待确认的差异点,口径闭环后评审定稿。 -- C2 主数据导入(人员、客户、产品):依赖 #9、#10、#11。 -- C3 订单 → 发货 → 回款导入:依赖 #1–#8、#13(成本、日期、分摊、核销、初始化)。 -- C4 负向事件处理(退货、红冲、负绩效):依赖 #8;口径已定为负绩效照公式出数、不归零。 -- C5 增量变更发现:依赖 #13;收付款表无 `updated` 字段,需验证 rowversion 与删除/作废的发现方式,在此之前时间水位保持禁用。 +### 节点 2:正式工资与 T+ 正式衔接(已完成) -### 轨道 D:交付收尾(依赖 A3 与轨道 C 完成) +- [x] 正式业务导入写入来源关联、输入版本和幂等保护,并衔接发货、回款与正式 `PayrollInput`。 +- [x] 正式 FIFO 逐段分配、期初先冲、预收、起付比例、重算级联、固化分管/交接和经理本人排除已落地。 +- [x] 月份首次生成锁、实际制作人限制、审批默认关闭、已生成工资走当月调整单已落地。 -- 本轮前置产出 `docs/T+交付部署设计_2026-10-28.md`:首期推荐任务计划程序,明确排队、进程恢复和业务重试的区别;周任务、阈值为设计默认,外部告警通道待确认。 -- D1 `tplus-worker` 托管(首期采用 Windows 任务计划程序)。 -- D2 每周同步任务编排与失败告警。 -- D3 客户内网独立部署与最终验收。 +### 节点 3:运维交付能力(已完成) -## 验收与保留门槛 +- [x] 每周自动排队、有限重试、心跳、停止标记和异常概况已实现。 +- [x] Windows 托管任务安装/管理/启动器及隔离运行验证已通过,默认禁用且不写入凭据。 +- [x] 全量与增量备份脚本改为永久留存口径,恢复演练脚本覆盖全业务表并对查询失败判为失败。 -- 未确认项不进入正式核算;确认单未闭环前不实施业务表写入。 -- 导入保护人工字段;每笔回款只核算一次;重算须授权并留痕。 -- 2008 R2 验收未完成前,2022 恢复副本的结果不作为同版本兼容证据。 -- 每个任务先完成定点测试再进入依赖任务;回归使用隔离的 MySQL/Redis。 -- C1 尾部按 #1–#13、L1–L7、B1–B5/M1–M5、S1 列出答复回填顺序。业务答复、字段存在、同版本实测和生产部署分别验收,不能互相代替。 -- S1 的暂缓加密是用户批准的当前开发阶段例外;生产敏感字段策略仍是上线前待确认项。 +### 节点 4:最终验证与证据(已完成) -## 项目后续路线 +- [x] 后端单元测试:`786 passed`。 +- [x] 隔离数据库集成测试:`406 passed`,失败 0、跳过 0。 +- [x] Ruff、前端 `vue-tsc`、Vite 生产构建和托管脚本隔离验证通过。 +- [x] 保留 Starlette/httpx 既有弃用提醒和 Vite 大包体积提示,均不影响本次功能验收。 -轨道 C 完成、A3 通过后进入轨道 D;部署验收通过即转入运维期(每周同步、参数调整走系统设置与版本管理)。 +### 节点 5:更正场景收口(已完成) + +- [x] 新增版本化 `CORRECTION` 事实,校验一正一负配对标识。 +- [x] 更正发货保留源快照并在预演/正式导入中排除绩效;跨客户回款按原业务标识归入,并在原客户侧自动排除。 +- [x] 补充前端事实录入、FIFO 单元测试和事实校验测试;客户确认的示例处理已落地。 + +### 节点 6:外部验收交接(待外部条件) + +- [ ] 真实样本补齐分类、指导成本、运费、期初/历史已处理金额和归属依据后,完成逐笔金额核对并扩大到整月。 +- [ ] 绑定目标环境实际工资制作人账号并验证生产权限;当前不使用测试账号代替生产授权。 +- [ ] 在 SQL Server 2008 R2 `10.50.1600` 目标环境完成连接、查询和兼容性实测。 +- [ ] 在客户目标环境完成周同步、服务托管、告警与全量/增量恢复演练。 + +节点 6 依赖客户资料、目标数据库和部署授权,不能用本地测试结果代替;其余仓库内开发任务已完成并进入交付等待。 + +用户已批准实施四阶段计划;以下原 Docker 预演计划及未完成项保留,最新业务约束以本节及客户新回执为准。 + +1. 权限与隔离:实际账号绑定制作人;测试库名称、显式标记和真实引擎目标同时校验;月结草稿首次成功生成即锁定该月分配,生成失败不锁,审批不解锁。 +2. 正式导入:复用源快照、稳定源身份、队列及预览指纹;新增 BUSINESS_PREVIEW/BUSINESS_APPLY。重复导入跳过,新增单据追加输入版本,旧金额/日期变化保留冲突。 +3. 正式核算:共享 FIFO 内核、期初先冲、预收待发货、60%起付与 R×R;正式台账逐段计提/应付差额独立记录;从指定月起可级联重算尚未生成工资的后续月份,已生成工资走当月调整。 +4. 归属与输出:每次发货对应业务员与当时分管经理,离职承接未发部分;经理本人业务排除。月结、报表与导出使用固化依据,调整单结构化关联原台账及分管。 + +## 新回执对计划的修订 + +来源:`docs/客户补充回执核对_2026-10-30.md` 与原回执副本。 + +- 第01项已明确:同一 T+ 发货客户名头下的合同合并为一笔业务平账。正式导入按账套内客户身份聚合,保留发货层的人员/分管/交接;不再要求每合同单独平账。 +- 第02项已明确:固定取发货月份指导成本,录入完成后封存,后续跨月回款不变价。 +- 第03项已确认一正一负更正单排除绩效、跨客户回款归入原业务;多原单金额分配与通用日期更正仍只阻塞相关特殊分支。 +- 第04项为“不涉及”:不新增保证金、代收款计提。 +- 第05项最新截图已明确:保留审核能力但默认关闭;关闭时工资生成即完成且不留审批痕迹,开启时使用原财务/领导流程。 + +## 验收与交付 + +新增 V18/V19 迁移、输入版本、FIFO明细与生成锁;迁移只能在隔离库验证,正式目标环境执行另按授权边界。已实现不等于已验收:完整单元、隔离集成、类型/构建及浏览器检查的最终结果统一记在开发记录。真实样本尚缺实际资料,不填默认成本、余额或虚假验收结果。 + +后续保留:多原单更正、SQL Server2008R2兼容、自动周同步、服务托管、告警、目标环境全量/增量恢复演练。备份文件不再按旧30天默认自动清理;本轮未运行清理或恢复脚本,不启用生产连接,不提交/推送。 + +--- + +## 上一阶段计划与原验收记录(保留) + +# 下一阶段开发计划:Docker 基础导入与核算预演 + +日期:2026-10-29。按本轮用户批准计划实施。此前计划原文保留在 [历史计划](archive/2026-10-28-tplus-pre-docker-plan.md),已有未提交内容一并保存。 + +## 本轮目标 + +恢复原 Docker 数据环境,先完成有依据的基础数据导入,再提供可追溯、可重跑的核算预演。预演不进入正式工资、月结、审批和发放。SQL Server 2008 R2 10.50.1600 兼容验收后置;虚拟机安装和屏幕控制不在关键路径。 + +## 已确认的开发约束 + +- 发货、到账日期取销货单、收款单的单据日期;销售和指导成本均含税,销售额剔除运费。 +- 绩效成本使用人工月度指导价,T+ 成本只留源快照,不导入绩效成本。 +- 回款采用明确分组内的 FIFO,不再强制合同关联;组范围、期初及历史已发款未明确时分别待补。 +- 人员按18人回执核对,工号保留前导零;不自动指定直属经理,不按姓名合并。 +- 仅导入客户性质往来单位,客户和产品核算分类允许人工维护,不做单位换算。 +- 经理本人业务排除;交接与经理分管保存独立事实,不覆盖当前人员关系推算历史。 +- 特殊抵顶继续线下;不创建清理任务,不新增生产账号或权限。 +- 全量读取、主键分页、哈希去重继续复用,时间增量关闭。源账号无写权限。 + +## 实施顺序与验收 + +| 阶段 | 已实施内容 | 验收信号与仍缺条件 | +|---|---|---| +| P1 环境及基线 | 原三容器恢复、九类源数据读取、当前指针、只读权限核验 | 当前源933203行;新增103359个历史版本来自补读单位、客户属性及凭证关联字段。2026-10-30原生ODBC连接、九类抽样和原worker重读已验证通过 | +| P2 规则与字段 | 日期、含税、客户性质、单位、人员名单核对;业务答复与字段证据分列 | 已核实收款到总账凭证的关联;13107张已有有效凭证、75张无关联不纳入本次预演,不以审核状态代替生成 | +| P3 基础导入 | 预览、执行、唯一源关联、人工字段保护、指纹失效、异常重试 | 实际17人导入,工号101124待核实;产品分类、客户属性不足的行保留待补 | +| P4 FIFO与预演 | 期初先冲、预收、逐段分配、冻结重跑、交接、经理排除、页面与CSV | 功能验证与客户验收分开;真实指导价、分组和历史资料不足,不能宣称整月工资对账通过 | + +## 最小数据与接口 + +V16/V17新增五张工作区表,head为 `07b8c9d0e1f2`。复用现有 `/api/v1/system/tplus` 和worker,新增事实及历史、源编号选择、工作区任务、分页明细和报告。正式核算表与预演表分开保存;原快照重跑不读取后来的成本、分类和参数。 + +## 业务并行事项 + +1. 平账范围:同客户统一还是按项目分开。 +2. 指导价:单位或总成本、发货月或回款月、历史处理。 +3. 历史承接:2026-02-28分组应收、已核算及已发款、8月参数。 +4. 交接及经理分管:时间、业务范围、双方人员与发货归属。 +5. 其他更正及特殊款:日期更正、保证金与其他职责;B04已于2026-10-30明确月度工资生成前可改、仅制作人可改、差额归调整单生成当月,不再追问。 +6. 逐笔复核:先以一个资料完整的平账组核对,再扩到整月。 + +未决条件只阻塞相关分支;已明确的日期、含税、指导成本与工号不重复询问。客户表见 `docs/核算预演补充确认清单_2026-10-29.xlsx`。 + +## 首轮结束标准 + +真实数据可导入,逐笔过程可核对,缺口能定位。完成定点、受影响模块、隔离迁移/集成回归、前端类型/构建和浏览器检查后交付。客户逐笔验收、原生驱动、2008R2兼容与生产部署分别记录,不混为完成。 + +验证细节见 `docs/T+基础导入与核算预演开发记录_2026-10-29.md`;任务状态见 `tasks/todo.md`。本轮不提交或推送,保留既有修改。 + +## 2026-10-30首轮样本与新回复 + +- 用户已授权按推荐选样本:辽阳精诚物业管理有限公司,2026-03,销货SA-2026-03-0034与收款SK-2026-03-0016各1125元;一个产品、一位业务员,关联凭证0035。 +- 已登记候选平账组pilot-9395-202603并运行待补预演;未确认开关保持关闭,未填默认指导成本、分类或期初余额。 +- B04新答复记录见docs/二次分配修改规则确认_2026-10-30.md;更正示例另按 `CORRECTION` 事实实现,不自动扩大至任意日期更正。正式工资入口按该规则的实现与验收已列节点 2、节点 5。 +- 真实字段核查纠正:SA_SaleDelivery.isCancel为结清状态枚举(428未结清、180已结清),不是作废布尔值;预演改按voucherState生效与实际红冲标志判断。 diff --git a/tasks/todo.md b/tasks/todo.md index 2ccae7e..9786bac 100644 --- a/tasks/todo.md +++ b/tasks/todo.md @@ -1,49 +1,126 @@ -# T+ 数据导入与同版本验收任务清单 +# 完整权限管理实施清单(2026-11-02) -依照 `tasks/plan.md`(2026-10-28)。上一轮清单已归档至 `tasks/archive/2026-10-27-tplus-sync-todo.md`。 +- [x] 按用户最新选择统一角色授权、授权版本和审计;取消个人覆盖及全局制作人绑定,工资月份锁与实际经办人留痕保留。 +- [x] V22 隔离升级/回退/再升级验证及本地全库备份;后续新模块接入 V25 兼容迁移。 +- [x] 用户“分配角色”与角色“配置权限”页面、统一菜单/按钮和只读提示已接入;轻动效支持减少动态效果。 +- [x] 最新 31+52=83 项隔离专项通过,覆盖授权撤权、版本冲突、并发保护、工资锁及审核;不将切换期间旧全量结果写成一次性全绿。 +- [x] 四类账号真实无模拟接口浏览器 6 项、全部路由权限覆盖及后台任务撤权通过。 +- [x] 完整单元 893 项、Ruff、前端类型/生产构建及本地前后台联通通过,使用与验证文档同步。 +- [ ] 并行角色改造任务完成本地 V26 应用与迁移记录;本聊天最后只读核查仍为 V25,隔离库 V26 已通过。 -## P0 工程收口 -- [x] 拆分提交本轮 T+ 同步管理成果(迁移、后端、前端、文档);提交前 Ruff、单元测试、前端类型检查与构建通过。 -依赖:无。 +--- -## P0.5 评审收口与交付设计 -- [x] 兼容脚本复用应用 URL 与连接文件校验,补特殊字符转义回归。 -- [x] 默认启用 TLS,模板说明显式回退、自签证书限制和私有配置迁移。 -- [x] 补本地恢复与同步开发手册,修正 A1 的容器/虚拟机步骤。 -- [x] 在现有客户版新增 S1,环境材料说明先用本地备份源同版本、生产信息后补;按用户决定保留旧 v2 删除结果。 -- [x] 产出 D1/D2 托管、每周排队、重试与告警设计稿。 -- [x] C1 补全每项预留决策的回填顺序。 -- [x] 完成隔离全量回归(1001 项)、Ruff、文档链接与表格保留校验;分代码和文档提交交付。 +# 历史同步运维及样本验收待办(2026-10-30) -## 轨道 A:同版本验收环境 -- [x] A1 细化 2008 R2 测试环境与验收手册(无介质可先做)。 -- [ ] A2 取得合法介质并安装备份源 10.50.1600 同版本环境。 -- [ ] A3 恢复原始备份并执行完整验收,产出报告。 -依赖:A2 等介质到位;A3 依赖 A2。 +> 2026-11-02 业务依据纠偏:第 01 至 05 项及 B04 已有当前口径。第 03 项以第二版回执和客户接受的聊天方案实施,不再向客户重复索要通用分配/日期规则;仅日后真实业务超出已确认场景时具体核实。依据见 `docs/业务规则时间线与当前口径_2026-11-02.md`。旧阶段待确认列表按历史保留,不作为当前催办清单;更正配对、排除校验、前端选择及完整流程验证仍归内部任务。 -## 轨道 B:业务口径确认 -- [ ] B1 发送 `docs/客户待确认事项表_2026-10-28_客户版.xlsx` 并跟进填写。 -- [ ] B2 回填经理个人户客户群反馈结果(L6)。 -- [ ] B3 答复回收后更新映射与暂定口径记录。 -依赖:无;B1 立即可发。 +- [x] T1:恢复库样本资料核对包,原始证据及指纹,候选期初/空运费不自动视为零。 +- [x] T2:默认关闭的每周周期检查、持久化状态、同周幂等、手动占用协调及停机只补最近周期。 +- [x] T3:明确断连/超时 5/15 分钟最多两次重试,人工恢复衔接,独立心跳和站内提示。 +- [x] T4:Windows 托管包及本机隔离验证,默认预演/安装禁用,账号、权限与动作核验。 +- [ ] T4 环境验收:专用目标环境服务账号、实际注册、开机触发、异常重启三次和停止不重领。 +- [ ] T5:首组真实金额验收;用户没有样本人工指导成本,保持待补,不填默认金额;随后再扩整月。 +- [x] T6:784 项完整单元、405 项完整隔离集成、迁移往返及16项专项、Ruff、前端类型构建、合成接口真实浏览器验证。 +- [x] 更新任务、样本缺口、开发记录和 Windows 操作说明,真实金额/生产启用单列。 +- [ ] 取得样本所需分类、运费、期初/历史与分管的实际依据后继续核对,不索要恢复库已有单据。 +- [ ] 实际制作人账号绑定、客户业务库迁移及生产自动化启用,均待目标环境确认。 +- [x] 第03项方案已有第二版回执及客户接受的聊天证据;既有实现记录保留,配对、排除、防重及页面操作的内部验证继续跟踪,不新增客户规则催办。 +- [ ] SQL Server 2008 R2 实机兼容、全量/增量恢复链单独验收。 -## 轨道 C:T+ 数据导入开发 -- [x] C1 起草 staging → 业务表写入设计,标注等待确认的差异点。 -- [ ] C2 主数据导入实现与测试。 -- [ ] C3 订单/发货/回款导入实现与测试。 -- [ ] C4 负向事件处理实现与测试。 -- [ ] C5 增量变更发现方案与验证。 -依赖:C1 无前置,可先行;C2–C5 依赖轨道 B 闭环与 C1 评审。 +详见 `docs/同步运维自动化与样本核对开发记录_2026-10-30.md`。下方原阶段记录保留,自动周同步/托管/告警的开发状态以上方为准,目标环境启用尚未完成。 -## 轨道 D:交付收尾 -- [ ] D1 worker 服务托管。 -- [ ] D2 每周同步任务与失败告警。 -- [ ] D3 客户内网部署验收。 -依赖:A3 与轨道 C 完成。 -说明:D1/D2 设计稿已产出,托管、周任务和外部告警尚未启用;生产主机条件与通道待确认。 +--- -## 检查点 -- [ ] 检查点 A:客户版业务答复完成并回填 C1(B01–B08、T01–T09);E01–E04 按环境与正式验收节点补齐。 -- [ ] 检查点 B:主数据导入通过,业务表首次写入可回滚。 -- [ ] 检查点 C:全量导入与 2008 R2 验收通过,进入轨道 D。 -- [ ] 上线前确认 S1 的全库敏感字段保护、保留期与备份访问策略。 +## 前一阶段待办与证据(保留) + +# 当前正式工资闭环验收清单(2026-10-30) + +## 本次收尾执行结果 + +- [x] 节点 1:接续既有计划与上下文,完成范围审计。 +- [x] 节点 2:正式导入、正式 FIFO、分管/交接、工资生成锁、审批开关和调整单链路已完成。 +- [x] 节点 3:自动周排队、有限重试、心跳、Windows 托管与永久留存备份脚本已完成并验证。 +- [x] 节点 4:单元 `786 passed`、隔离集成 `406 passed`,Ruff、前端类型/生产构建和托管脚本验证通过。 +- [x] 节点 5:客户确认的更正发货排除与跨客户回款归属已实现,并补充回归测试。 +- [ ] 节点 6:真实样本、实际制作人、SQL Server 2008 R2 目标环境和正式恢复演练待外部条件满足后验收。 + +> 当前工作区不提交或推送;本文件只记录本次执行状态,外部验收未完成前不将项目标记为全部交付。 + +- [x] 加入隔离库硬校验、指定制作人身份与首次生成锁;单位/模块测试已有通过证据。 +- [x] 实现正式业务导入、源身份防重、输入版本及正式FIFO逐段过程。 +- [x] 实现未生成工资月份级联重算、重算原因留痕、固化分管和结构化当月调整。 +- [x] 核对新回执:01客户名头合并、02发货月指导价封存、04不涉及已明确;05审核保留默认关闭;03示例处理已确认并实现。 +- [x] 最终完整单元749项通过(新回执修订后)。 +- [x] 最新完整隔离集成全部29文件分组覆盖,215+184=399项通过;V18/V19迁移往返与结构9项通过。 +- [x] 前端类型、生产构建、合成数据真实浏览器表单/默认无审核入口通过;客户使用验收另列。 +- [ ] 真实样本完整金额逐笔核对,再扩大到整月。 +- [ ] 补录实际制作人账号并在目标环境验证,不以测试账号代替生产授权。 +- [x] 第03项已确认示例的更正分支已收口;多原单通用分配及任意日期更正仍按边界保留。 +- [ ] 2008R2兼容、每周同步、托管、告警和目标环境恢复演练。 + +以下原阶段任务及未完成项保留;其中旧“按独立业务分组”“成本月份待答复”等说法由上方新回执修订,不再重复向客户追问。 + +--- + +# Docker 基础导入与核算预演任务 + +依照 `tasks/plan.md`。旧清单原文保留在 `tasks/archive/2026-10-28-tplus-pre-docker-todo.md`。 + +## P1 环境与基线 + +- [x] 恢复原 SQL Server、MySQL、Redis 容器,保留数据目录和恢复库。 +- [x] 九类读取完成,当前933203行,新增字段导致历史版本增加103359行,差异已解释。 +- [x] 只读账号写权限为0;全量、主键分页和哈希去重沿用,时间增量关闭。 +- [x] 2026-10-30用户安装ODBC18后,原生只读连接、九类抽样查询及原worker完整重读19178条通过;新增0、失败0,正式表不变。证据见docs/T+原生连接验收记录_2026-10-30.md。 + +## P2 字段和规则 + +- [x] 固定客户原始回执来源,人员事实逐行带单元格与SHA-256,不复制生产凭据。 +- [x] 日期、含税、人工指导价、客户性质、源单位核对;停用T+绩效成本映射。 +- [x] 18人核对:17人匹配,工号101124缺失,不按姓名合并。 +- [x] 生成字段/规则差异表及六项客户补充确认表。 +- [x] 字典与真实总账关联交叉核实生成凭证路径,13107张已有有效凭证,75张无关联不纳入本次预演;未审不等于未生成。 + +## P3 基础导入 + +- [x] 管理员预览、排队导入、分页结果与CSV报告。 +- [x] 稳定源身份、幂等、指纹失效、人工字段保护、冲突与待补。 +- [x] 实际17人导入,重复预览不新增;工资、发货、回款、台账和月结未写入。 +- [x] 产品77072行及纯客户5049行保留待补,非纯客户2907行跳过。 +- [ ] 客户补例单所需分类、负责人及缺失工号后,重预览并逐类导入。 + +## P4 核算预演 + +- [x] 固定快照、月份、指导成本与参数,原快照重跑可复现。 +- [x] FIFO稳定顺序、先旧后新、预收余额、成本尾差与金额守恒。 +- [x] 交接和经理分管独立登记,经理本人业务排除,人工分类优先。 +- [x] 运费逐明细扣除,未核实不默认为0;日期更正保持禁用。 +- [x] 可用页面、逐笔明细、待补说明及报告;正式核算状态保持不变。 +- [ ] 客户补分组、期初、历史已发款、月度指导价和交接依据,完成一组真实业务复核。 + +## 验证与交付 + +- [x] 隔离迁移:空库升级、V17/V16回退、再次升级通过。 +- [x] 完整392项隔离集成回归通过;凭证映射补入后13项相关复核通过,单元702项通过。 +- [x] 新增工作区MySQL权限、事实、队列、完整预演与冻结重跑,加结构复核共13项通过。 +- [x] 最终Ruff、差异空白检查、前端类型/构建与新字段页面收口。 +- [x] 浏览器真实任务、7956行CSV、历史、前导零、表单取消及320/768/1024/1440宽度通过,无页面错误。 +- [x] 完成最终开发记录与回归证据回填。 + +- [x] 凭证排除分支收口后的最终完整隔离集成回归:392项通过、退出码0,764.72秒;句柄22149已正常结束,证据.ai/workbench-regression.log。 + +## 2026-10-30新增回复与首轮样本 + +- [x] 接收B04三条明确答复,单独记录并从客户表移除重复追问,未改原始回执。 +- [x] 真实查询筛选并选取辽阳精诚物业管理有限公司2026年3月一发一收样本,生成单页核对表。 +- [x] 候选平账组登记,未确认开关关闭,待补预演PARTIAL,正式表不变。 +- [x] 实测结清枚举,修复非零结清状态被误判作废;最新单元710项、完整隔离集成392项、相关集成与结构13项、前端构建和真实样本页检查通过(规则2026-10-30.1,完整回归795.36秒、退出码0)。 +- [ ] 收到样本分类、指导成本、运费、期初/历史款及归属答复后,完成实际金额预演。 + +## 后续阶段(本轮不计完成) + +- [ ] SQL Server 2008R2 10.50.1600兼容验收。 +- [ ] 负向事件正式处理、正式工资生成、月结和发放联动。 +- [ ] 时间增量、自动周同步、服务托管与告警、生产授权及部署。 + +- [ ] B04正式功能:按月度工资生成节点锁定、按实际工资制作人限制修改,已结算差额归调整单生成当月;已有业务角色或审批权限不能代替此项验收。 diff --git a/tasks/需求补齐计划_2026-11-02.md b/tasks/需求补齐计划_2026-11-02.md new file mode 100644 index 0000000..120b092 --- /dev/null +++ b/tasks/需求补齐计划_2026-11-02.md @@ -0,0 +1,15 @@ +# 需求补齐实施计划(2026-11-02) + +依据用户批准的完整计划实施,不覆盖原有部署、权限及监控工作。原需规 16 个小节的页面能力均纳入最终对照。 + +- [x] F07 系数表维护、阶段/户型/产品分类、Excel 模板/预览/确认/导出、版本历史与对比。 +- [x] F01/F02 正式核算、预演及试算统一取参;企业户分类比例、信息员销售额计提。 +- [x] F03 基本工资按人一次、无绩效发薪、试用期日期及缓发台账、年终和跨年续付、页面及导出。 +- [x] F04 指导单位成本与总成本校验、毛利润视图联动及历史封存保护。 +- [x] F05/F06 最近有效发货数量/单价与来源、人工保护、业务提取产品预览/执行及页面。 +- [x] 增量迁移及初始化同步、单元/隔离集成、类型/构建/浏览器验证。 +- [x] 新版 Word(原 16 小节)与逐项实现/验收记录,原文保留。 + +已确认口径:系数由公式生成并以参数版本为唯一来源;试用期仅累计试用期间计提,18000 元超额同时受业务起付和平方权重限制;产品展示最近有效发货数量及含税成交价,附来源。实际资金支付、未明确的通用多原单更正、生产启用不在本次范围;不提交或推送。 + +验收证据:899 项单元通过;32 个集成文件分组 A211+B213 通过,年度续付专项5项通过;类型/构建/Ruff及9组真实浏览器操作通过;Word保留16小节并渲染5页检查。详细边界见 docs/需求补齐实施与验收记录_2026-11-02.md。