- 平台首个 kind=write 工具,研发/运维专用 scope 门禁,无行级权限 - 按单号改派出库/入库/调拨/划转单当前待办处理人:UPDATE 流程物理表 warehouse_out_audit_process / warehouse_in_audit_process / warehouse_allocati_process 的 schedule_state=1 待办行 user_id/user_name,补 modify_id/modify_time - 调拨/划转按 warehouse_allocation.op_type(0/2) 一致性校验;并行待办行全部改派 - 新处理人按手机号查 m0 user(soft_delete=0 精确匹配);服务身份 Token 拒绝 - 新增 WarehouseAllocatiProcess 实体+Mapper,WarehouseAllocation 补 orderState 列 - 525 tests 全绿(+10)
8.0 KiB
8.0 KiB
仓库单据处理人改派 MCP 工具设计(warehouse.order.handler.update)
- 需求:REQ-20261107-0002(ai-proj id 6442)
- 状态:已评审通过(2026-11-07 王恒拍板:入参=单号+手机号,手机号查 m0 user 表带 soft_delete=0 条件,其余按建议)
- 日期:2026-11-07
1. 背景
运维/研发场景需要把"卡"在某个处理人名下的仓库单据待办改派给他人(人员离职、调岗、账号停用等)。 老系统(xiaoqu-franchisee)没有"修改处理人"接口(已全仓检索确认),目前只能靠人工改库。 本需求提供 MCP 写工具完成改派,访问控制完全靠专用作用域(scope)门禁,不做行级权限。
这是 agent-service 的首个 kind=write 工具(ToolKindRegistry 已预留 write 注解: readOnlyHint=false / idempotentHint=false / destructiveHint=true)。
2. 调研结论(行号级依据)
2.1 四类单据的表结构
| 单据 | 主表(m2) | 单号列 | 流程物理表 | 流程视图 |
|---|---|---|---|---|
| 出库单 | warehouse_out |
out_order_no |
warehouse_out_audit_process |
warehouse_out_process |
| 入库单 | warehouse_in |
in_order_no |
warehouse_in_audit_process |
warehouse_in_process |
| 调拨单 | warehouse_allocation(op_type=0) |
allocation_order_no |
warehouse_allocati_process |
warehouse_allocation_process |
| 划转单 | warehouse_allocation(op_type=2) |
allocation_order_no |
同上 | 同上 |
注意:
- 调拨/划转是同一张表,靠
op_type区分(0调拨/1采购/2划转, 见 beans/b2/WarehouseAllocation.java:86)。 - 流程物理表名是
warehouse_allocati_process(少一个 on,历史拼写,勿写错), 视图warehouse_allocation_process才是全名。 - 视图
*_process只读展示用;写必须落物理表*_audit_process/warehouse_allocati_process。
2.2 "当前处理人"的存储语义
- 流程表中
schedule_state=1(待办)且soft_delete=0的行,其user_id/user_name即为当前处理人(beans/b2/WarehouseOutProcess.java:54、WarehouseAllocationProcess.java:80; agent-service 的 WarehouseTodoTools 也是按user_id = 当前登录人 AND schedule_state=1认定待办归属)。 - 老系统审批/确认动作均校验操作人 == 待办行 user_id (如 WarehouseAllocationController.java:403-409 先按 schedule_state=1 取当前用户待办行再办理)。
- 因此改派 = UPDATE 待办行的 user_id / user_name(并按仓库规范补 modify_id/modify_time)。
- 一张单同一时刻可能有多条并行待办行(多人会审),也可能为 0 条(已完成/已撤销/作废/无需待办)。
2.3 agent-service 现状
- 本地已有实体/Mapper:
WarehouseOut/WarehouseIn/WarehouseAllocation/WarehouseOutAuditProcess/WarehouseInAuditProcess(含 Mapper)。 - 缺:
warehouse_allocati_process的本地实体与 Mapper(需新增, 参照 beans/b2/WarehouseAllocatiProcess.java 全列复制——PR #30/#31 教训: publicbeanandmap 不是 Maven 依赖,必须本地拷贝且列要全)。 - 新处理人校验用 m0
user表(本地实体me.iiv.agent.entity.m0.User已存在)。 - 审计写 svc 库
audit_log(实体me.iiv.agent.entity.svc.AuditLog已存在, 字段含 userId/tokenId/toolName/paramsDigest/requestId 等)。
3. 工具设计
3.1 工具定义(1 个工具)
warehouse.order.handler.update kind=write category=admin
参数:
| 参数 | 必填 | 说明 |
|---|---|---|
| orderType | 是 | 枚举:out 出库单 / in 入库单 / allocation 调拨单 / transfer 划转单 |
| orderNo | 是 | 单据编号(精确匹配,去空格) |
| newHandlerMobile | 是 | 新处理人手机号(m0 user.mobile 精确匹配,拍板定案:只认手机号) |
| memo | 否 | 改派原因,写入审计日志 |
行为:
- 按 orderType 路由到对应主表,按单号精确查询(soft_delete=0),不存在 →
NOT_FOUND。 - 一致性校验:
allocation要求 op_type=0,transfer要求 op_type=2,不符 →INVALID_ARGUMENT(防止把调拨单号当划转单改)。 - 查该单流程物理表中
schedule_state=1 AND soft_delete=0的待办行;0 条 →NOT_FOUND「该单据当前无待办处理人(已完成/已撤销/作废)」,并返回 orderStateText。 - 新处理人校验:m0 user 存在且 soft_delete=0,否则
INVALID_ARGUMENT。 - UPDATE 所有待办行:
user_id、user_name(取 user 表真实姓名)、modify_id=调用方 userId、modify_time=now。 - 写 svc
audit_log:调用方 userId/tokenId、工具名、参数摘要 (orderType/orderNo/新旧处理人/memo)、request_id。 - 返回 before/after。
返回结构:
{
"orderType": "out",
"orderNo": "OUT20261001001",
"orderId": 12345,
"orderState": 2,
"orderStateText": "待出库",
"changedRows": [
{"processId": 9001, "oldUserId": 101, "oldUserName": "张三",
"newUserId": 205, "newUserName": "李四"}
],
"changedCount": 1,
"requestId": "..."
}
报错沿用 ToolCallException 透出风格(INVALID_ARGUMENT / NOT_FOUND_OR_FORBIDDEN / DATA_INTEGRITY_ERROR)。
审计说明:GuardedToolCallback 已对每次调用自动写 svc audit_log(操作人 userId/tokenId、 参数摘要、结果状态),工具内再以 request_id 打一条 before/after 服务端日志,两者合一可追溯。
3.2 权限与作用域(核心拍板点已按用户口径定)
- 不做任何行级权限,不调用 PermissionService 行过滤;任何单据都可改。
- 访问控制 = scope 绑定:工具上线后只绑用户新建的"研发专用" scope (不绑 1/2/3/5,seed-dev.sql 也不预绑任何 scope)。
- 服务 Token(principalType=service)只能签 SYNC 作用域,天然调不到本工具; 调用方必须是持有该专用 scope 的用户委托 Token。
- 审计兜底:audit_log 记录每次调用的操作人 token 身份,事后可追溯。
4. 与老系统差异 / 风险说明
- 老系统无此功能,MCP 为新增能力,无兼容包袱。
- 改派只动流程表待办行,不动主表、不重推审批流、不发消息通知 (老系统审批动作会触发消息,改派属于运维动作,是否通知新处理人见拍板点 5)。
- 改派后新处理人在老系统 App/PC 端即可正常看到待办并办理(语义等价于原处理人办理)。
- 视图
warehouse_allocation_process.next_user_name等冗余字段由视图实时计算,无需同步改。
5. 拍板结论(2026-11-07 王恒已拍板)
- 1 工具 + orderType 枚举 ✅(不拆 4 个)。
- 新处理人入参:只认 mobile 精确匹配(拍板定案,去掉 userId 入参);
手机号查 m0 user 必须带
soft_delete=0条件。 - 并行多条待办行:默认全部改派并逐行返回。
- 不加 dryRun(返回已含 before/after,audit_log 可追溯)。
- 不发系统消息(运维动作,避免惊动业务消息流)。
6. 改动文件清单
| 文件 | 动作 |
|---|---|
entity/m2/WarehouseAllocatiProcess.java |
新增(全列本地拷贝) |
mapper/m2/WarehouseAllocatiProcessMapper.java |
新增 |
mcp/tool/WarehouseOrderAdminTools.java |
新增(1 个工具方法) |
mcp/tool/WarehouseOrderAdminToolsTest.java |
新增(参数校验/单号不存在/op_type 不一致/无待办行/并行多行/新处理人不存在/审计写入) |
doc/agent-mcp-tools-reference.md |
追加工具章节 |
README.md |
工具表登记 |
装配层零改动(组件扫描自动注册)。seed-dev.sql 不预绑 scope。
7. 上线步骤
- 全量
./mvnw clean package绿 → push main → remote-deploy。 - 王恒已建好"研发专用" scope(2026-11-07 确认)→ 查 scope id 后在 prod svc 库
INSERT IGNORE INTO scope_tool(scope_id, tool_id)只绑该 scope。 - 生产冒烟:用专用 scope 签用户 Token,对一张测试单改派 → 验证老系统待办归属变化 → 改回。