申购单文件夹自动分拣与调度

SKILLAI 工具
AI 工具 未标注权限 许可证不明确
安装这个技能

多类型申购单文件夹统一调度工具:自动扫描并用「文件名+表头特征」把每份文件归类为零件BOM/电气件/紧固件/外购件/零散物料,再依次调度对应「处理」skill 匹配编码、生成金蝶导入模板。导入模板共用一个 导入模板.xlsx,生成前必须停下等用户确认。触发词:分拣申购单、批量匹配、一堆申购单、多个申购单一起、自动分辨申购单类型、文件夹匹配。

一句话选型结论

按资料字段整理

申购单文件夹自动分拣与调度是AI 工具类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类AI 工具 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_d201725d/requisition-dispatcher
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

AI 工具
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_d201725d仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791681187
正文体量33.5 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
组合多个 AI 能力

把写作、检索、总结串成一条流程。

搭工作流

把固定流程做成可重复调用的步骤。

做提示词与评测

整理提示词并对比输出效果。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在AI 工具场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
申购单文件夹自动分拣与调度当前 未标注权限 未标注 未标注 未标注 有
执行计划 只读 GitHub 仓库 151.5 万 Codex、Claude、Cursor 有
Playwright MCP 测试 浏览器控制 ClawHub 市场 136.5 万 OpenClaw 有
完成前的验证 未标注权限 GitHub 仓库 131.9 万 Codex、Claude、Cursor 有
子 Agent 驱动开发 只读 GitHub 仓库 131.2 万 Codex、Claude、Cursor 有
前端设计 执行命令 GitHub 仓库 125.6 万 Codex、Claude、Cursor 有

SKILL.md 全文

33.5 KB
模型实际读到的说明书原文,来自技能仓库

申购单文件夹自动分拣与调度

适用场景

用户把多种类型的申购单(零件BOM、电气件、紧固件、外购件、零散物料)以及可能的物料数据库,
全部放进同一个文件夹,希望我自动分辨类型、调用正确的「处理」skill 把编码填回去,
再(经确认后)调用正确的「处理」skill 生成金蝶导入模板。

四类各自有独立的「处理」skill(含匹配+导入),本 skill 不重复实现匹配/导入逻辑,而是调度它们:

类型 处理 skill(含匹配+导入) 匹配字段
零件BOM 零件BOM处理 名称+规格+品牌+材质+表面处理(五字段精确)
电气件 电气件处理 品名+规格+品牌+单位(四字段精确)
紧固件 紧固件处理 品名+规格+材质+表面处理(含表面模糊)
外购件 scripts/match_waibuy.py(本 skill 内置) 名称+规格+品牌(三字段精确,命中回填编码,未命中标「未匹配」提示)
零散物料 零散物料导入 提取编码列为空的行,A/B/C 系列新建

> 注:匹配/导入脚本已内嵌在各「处理」skill 的 scripts/ 内(自包含,不再依赖独立匹配/导入 skill)。本 skill 通过加载对应「处理」skill 并运行其 scripts/ 下脚本完成调度。

> 💡 单一类型快捷入口:如果用户只给了一份某类型的申购单(不是混装文件夹),不必走本分拣流程,
> 直接调用对应的「匹配+导入一体」skill 即可一键完成 匹配→(确认)→导入→(金蝶确认后)回填:
> - 零件BOM → 零件BOM处理
> - 电气件 → 电气件处理
> - 紧固件 → 紧固件处理
> 这些一体 skill 已内建三道确认门禁(匹配预览、导入生成、金蝶后回填),与本流程安全规则一致。
> 本分拣 skill 仍专用于多种类型混在一个文件夹的统一调度场景。

核心约束(务必遵守)

> 🔴🔴 桌面只留最终文件,备份/证据不留桌面(2026-09-16 用户明确要求)
> 用户原话:「以后桌面上我只想看到最终的 你备份的和证据都帮我删除」。
> - 禁止把 .bak.xlsx、.污染留存.xlsx、*备份*、*证据* 留在桌面等用户可见目录。
> - 备份/证据放工作区临时目录(D:\ai\<session>\,_ 前缀),收尾时自行删除,不必等用户开口。
> - 任务结束桌面应只剩:用户原始文件 + 最终交付件 + 物料表。
> - 删前先做完整性核对(如「编码→物料表反查名称」),确认最终件完好再删。
> - 删除须走回收站(可恢复)。实测可用/不可用:
> · ❌ send2trash —— 含空格/中文长路径报 ProcessLookupError: [Errno 3]
> · ❌ PowerShell Add-Type / New-Object -ComObject —— 被安全策略拦截
> · ✅ Python ctypes 调 shell32.SHFileOperationW(FO_DELETE + FOF_ALLOWUNDO)
> · ✅ [Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile($p,'OnlyErrorDialogs','SendToRecycleBin')
> 验证入站:读 C:\$Recycle.Bin\<SID>\$I*(UTF-16 含原路径);shell 里写 $Recycle.Bin 的 $ 会被转义,用 Python/PS 直接构造。

> ⚠️ 导入模板共用一个 导入模板.xlsx(D:\莫佩琪\msl\导入模板.xlsx,由 _shared/paths.py 管理,可用 MSL_DIR 环境变量覆盖)。
> 零件BOM / 电气件 / 紧固件 / 零散物料 四个导入流程同时导入会互相覆盖。
> 因此:生成导入模板这一步绝对不能自动串着跑,必须停下来等用户逐类确认。

> ⚠️ 匹配可全自动(只是把编码填回申购单原文件,原地改,安全)。但默认先 --dry-run 预览匹配率,用户确认后再真写。

> ⚠️ 编码回填遵循「确认后回填」:导入模板上传金蝶、用户确认全部成功后,才把新编码回填进申购单空编码列;未确认绝不填。

> ⚠️ 子 skill 版本更新自动生效:本 skill 是「瘦路由」,不复制匹配/导入逻辑,只做分类与调度。实际匹配/导入由我加载对应「处理」skill 的最新 SKILL.md 与 scripts/ 现场执行(脚本已内嵌在各处理 skill 内,自包含),每次都从磁盘读最新版。因此任一处理 skill 升级后,下次分拣自动使用新版本,无需改动本 skill。唯一注意:若某处理 skill 重命名了脚本文件名或大幅改动 CLI 参数,本 SKILL.md 里对该脚本名的引用需同步更新;但执行时我以加载到的处理 skill 实际说明为准,会自行校正。

> 📦 本 skill 自包含(2026-09-29 起):除调度外,match_waibuy.py(外购件匹配/回填)自带一份
> in-skill _shared/,与另外 4 个「处理」skill 同等的自包含约束(母本 skills/_shared/ 为单一真源,
> 由 python sync_shared.py 同步、tests/test_shared_in_sync.py 逐字节守护)。
> 之所以必须自带:此前本 skill 的 match_waibuy.py 靠 sys.path 复用仓库根 _shared/,
> 本地能跑,但单独打包发布到 skillhub 后安装目录里没有 _shared/ → ModuleNotFoundError
> → 发布出去的「申购单分拣」直接不可用。现导入写法已统一为 from _shared.xxx import ...(行为零变化)。

> 🔴🔴 备注列绝不做信息筛选(2026-09-12 用户两次明确要求,通用铁律,适用全部 5 类):
> 申购单「备注」列 = 普通备注列,只由 _shared/normalize.build_remark() 按原规则处理(重量前缀 + 原备注 + 表尾备注),
> 不得对备注内容做任何筛选/判别/分流,更不得把备注内容写进模板其他列(尤其金蝶「表面处理」字段)。
> 申购单若只有备注列、无独立表面处理列 → 模板表面处理列留空。禁止为备注列新增 strip_weight_prefix /
> looks_like_surface / clean_surface 之类「从备注推表面处理」的逻辑(曾试做,已全部回滚)。
> 用户原话:「备注列的信息不加入表面处理」/「申购单上的信息都在备注,备注你只要按照你以前的规则处理就行,不用筛选填到模板的表面处理列或者别的列」。

前置条件

  • Python 环境:C:\Users\mpqtc\.workbuddy\binaries\python\envs\default\Scripts\python.exe;依赖见本 skill 目录 requirements.txt(openpyxl>=3.0,<4、xlrd>=1.2.0,<2.0)
  • 执行方式:脚本调用一律用 Python 绝对路径,形如
    cd "<skill目录>" && PYTHONIOENCODING=utf-8 "<python绝对路径>" "scripts/xxx.py" ...;
    文件操作(备份/拷贝/删除/列目录)优先交给 Python(shutil、ctypes.SHFileOperationW 走回收站);
    读文件用 Read 工具、查文件用 Glob/Grep(工具选择规范,与 shell 是否可用无关)。
    > ⚠️ 2026-09-29 订正:此前记录的「本机 bash 工具残缺,ls/cp/mkdir/head/tail 一律报
    > command not found、PowerShell 输出可能为空」(2026-09-20 实测)已过时 —— 2026-09-29 实测这些命令
    > 均恢复正常可用,管道(| head)也正常。故 ls/cp/mkdir 与管道可以直接用,不必再一律绕行 Python。
    > 自检口诀:命令报 command not found 或 PowerShell 无输出 → 才改走 Python 绝对路径,别反复重试 shell。
  • 四个处理 skill 已安装:零件BOM处理 / 电气件处理 / 紧固件处理 / 零散物料导入 需位于 ~/.workbuddy/skills/ 下(本 skill 只做分类与调度,实际匹配/导入由对应 skill 的脚本执行,每次从磁盘读最新版)
  • 共用的导入模板:D:\莫佩琪\msl\导入模板.xlsx(金蝶 71 列格式;MSL_DIR 环境变量可覆盖)
  • 待分拣文件:多类申购单放在同一目录(如桌面),.xls / .xlsx;不支持 .xlsb
  • 物料表:金蝶导出 物料_*.xlsx,自动探测顺序 = 桌面(Desktop / 桌面 / OneDrive 重定向)优先 → MSL_DIR

工作流

Step 1:扫描 + 分类

用本 skill 的 scripts/classify.py 扫描文件夹:

PYTHONIOENCODING=utf-8 python "scripts/classify.py" "<文件夹路径>" [--material 物料表路径] [--json]

脚本输出一份分类报告:文件名 / 类型 / 置信度 / 判定理由,并列出检测到的物料候选。

  • 类型取值:物料数据库 / 零件BOM / 电气件 / 紧固件 / 外购件 / 零散物料 / ⚠未知
  • 置信度 low 或类型为 unknown 的文件,必须让用户确认类型,不要瞎猜。

Step 2:用户确认分类

把分类报告呈现给用户。若有 unknown / low 或用户认为分错的,先纠正再继续。
(用户一般会把文件命名成 电气申购单 / 紧固件申购单 / 零件BOM / 零散物料,文件名权重最高。)

Step 3:逐份跑匹配(先 dry-run 预览)

对每个申购单(不含物料数据库、不含零散物料),按其类型加载对应「处理」skill,先 --dry-run 预览:

  • 零件BOM → 加载 零件BOM处理 skill,跑 scripts/match_bom.py <申购单> <物料表> <输出.xlsx> --dry-run
  • 电气件 → 加载 电气件处理 skill,跑 scripts/match_electrical.py <申购单> <物料表> <输出.xlsx> --dry-run
  • 紧固件 → 加载 紧固件处理 skill:
  • 表头有「品牌」列 → scripts/match.py <申购单> <物料表> <输出.xlsx> --with-brand --dry-run(五字段)
  • 无品牌列 → scripts/match.py <申购单> <物料表> <输出.xlsx> --dry-run(四字段)
  • 外购件 → 跑 scripts/match_waibuy.py <申购单> <物料表> [--dry-run] [--all-sheets](名称+规格+品牌 三字段精确匹配,命中回填编码、未命中在「匹配详情」列标「未匹配」)

> 🔎 外购件「疑似复用候选」报告(v1.3.0 新增,只报告不写入):外购件清单的品牌列常写「淘宝」(购买渠道而非真品牌),
> 而物料库里同物料的品牌字段多为空 → 三字段精确匹配落空。脚本会在汇总后附一段
> 「疑似复用候选」:列出未匹配行中在物料库已有「同名同规格」旧码(仅品牌不同)的项及其候选编码。
> 脚本绝不自动采用,须人工判断是复用旧码还是建新码(防重复建码,对齐 M26016 事故教训)。
> 自检口诀:外购件一批未匹配里若有多条「同名同规格但品牌空」→ 先看疑似复用候选,别直接建新码。

> 🔴 多 sheet 申购单必须加 --all-sheets(4 个匹配脚本口径已统一,2026-09-21)
> 申购单常把多页做成多个工作表(外购件如 ZMSH0001-…外购件清单.xlsx 含 清单01~清单04;
> 电气件如 ZMSH001电气采购单.xlsx 含 清单1+清单2)。
> 4 个匹配脚本(match_waibuy.py / match_bom.py / match.py / match_electrical.py)现在行为一致:
> 默认只处理第一张表,但只要工作簿含多 sheet 就会打印 ⚠️ 警告并提示 --all-sheets(不再静默跳过)。
> - 多 sheet 单据:加 --all-sheets 一次跑全部表;或 --sheet <表名> 只跑指定表。
> - ⚠️ 加 --all-sheets 前先确认每张表都是真清单 —— 申购单里可能夹带历史草稿表
> (实测 M26016-M01…紧固件申购单.xlsx 活动表是真清单 3 行,另带 2 张 330+ 行的历史草稿)。
> 看到 ⚠️ 警告别条件反射加 --all-sheets。
> - 复核阶段 audit.py(≥v1.4)已遍历全部 sheet,不会漏审。
> 自检口诀:① 文件名带「采购单/清单」但只有几十行、页脚写「第 1 页 共 2 页」→ 先看 sheetnames,别只跑活动表;
> ② 命中率异常低 / 未匹配条数明显偏少 → 先看是不是多 sheet 只跑了一个。

> 锁定测试:tests/test_multisheet.py。
- 零散物料 → 无匹配步骤,跳过(直接进入导入)

> 第三参 <输出.xlsx> 与子 skill 命令保持一致(dry-run 预览时不写文件,可填 <申购单> 表示原地修改路径)。各匹配脚本默认原地修改源文件。

> 💡 备注栏合并自动取消(2026-08-11 起):各「处理」skill 在匹配/生成前会自动跑 _shared/unmerge_column.py,取消备注栏(按表头定位)的纵向合并并填充内容到每一格(因匹配脚本写备注时只解除合并、只写左上角,先取消合并才能避免次行变空)。本分拣流程无需额外处理,调度各处理 skill 时即自动生效。已无合并则幂等跳过。

把每份单的匹配成功数 / 未匹配数汇总给用户看。

Step 4:预览后直接写回编码(无需确认)

按 2026-07-20 规则「匹配写回不需要确认」,Step 3 的 --dry-run 预览后直接去掉 --dry-run 重跑各匹配脚本,原地填回编码到申购单,不再单独停下问确认。

> 注意:匹配脚本默认原地修改源文件(.xls 不支持原地改,需先另存 .xlsx)。写入前提醒用户关闭 Excel。

Step 5:收尾强制复核(防漏处理,必须执行)

> ⚠️ 每次分拣,写回编码后、确认导入前,必须跑 scripts/audit.py 做一次全量复核。
> 它的作用是:扫描分类出的每一份申购单,检查编码列是否真的被填过——若发现某份编码列全空、无任何「未匹配」标记、且有真实数据行(即匹配脚本根本没跑过),立即报 UNPROCESSED 并 exit(1),禁止收尾。
> 这正是本次(M26013 零件BOM 被漏处理)这类问题的根因:分类列了 N 份,执行时凭记忆少跑了 1 份,最后没对账。

PYTHONIOENCODING=utf-8 python "scripts/audit.py" "<文件夹路径>" [--material 物料表路径]

audit.py 输出每份申购单的完成度:

状态 含义 处理
DONE 全部数据行已填编码 ✅ 通过
NEEDS_IMPORT 有「未匹配」行(需新建编码) 正常,进入 Step 6 确认导入
UNPROCESSED 编码列全空且无任何标记、有真实数据行 → 匹配脚本没跑过 ❌ 必须补跑对应匹配 skill,再回来复核
PARTIAL_EMPTY 部分数据行既无编码也无标记 ❌ 需核对,可能漏处理

> 📌 v1.4 起遍历全部 sheet:多 sheet 申购单(如 ZMSH001 的 清单1+清单2)各表独立审计后汇总计数,
> 任一表不过即不过。同时表头行改为按「标识列表头最多的行」定位,页脚行(第 N 页 共 M 页)用正则识别。
> 这三处修复共同消除了「PARTIAL_EMPTY 假警报」(实测误报 11 行)。

复核不过(出现 UNPROCESSED / PARTIAL_EMPTY)绝不许进入 Step 6 导入确认,必须先补齐处理、再次跑 audit.py 直到全绿(全部 DONE/NEEDS_IMPORT)。

> 🔴 DONE 也可能是假绿 —— 维度声明损坏(2026-09-15 加固,audit v1.3)
> audit.py 曾用 read_only=True 加载工作簿。read_only 模式下 openpyxl 信任 xlsx 里声明的
> dimension
,而金蝶导出的表有 declared dimension = A1:A1 的毛病 —— 实测物料表
> ws.max_row 读出 1、实际 28983 行。若某份申购单也带此毛病,主循环
> range(hr+1, ws.max_row+1) 一行都不遍历 → filled=unmatched=unmarked_empty=0
> → 命中 DONE(空数据文件)分支,把「一份都没复核」伪装成「复核通过」。
> 已改为非 read_only 加载(max_row 由实际解析到的单元格推导,天然免疫)。
> 申购单通常几百行,全量加载代价可忽略;物料数据库已被 classify 过滤、不进 audit。
> 已实测无效的绕法,勿再试:
> · ws.reset_dimensions() —— 只把 max_row/max_column 置 None 不重算,detect_code_column 里 range(1, None+1) 直接 TypeError;
> · ws.calculate_dimension(force=True) —— read_only 下仍回读声明值 'A1:A1';
> · read_only 下 iter_rows() 计数 —— 大表上直接卡死(曾在此 28983 行表上被 SIGTERM)。
> 自查口诀:见到 DONE 但 已填 列是 0、而这份单子明明有数据行 → 先怀疑维度声明,别直接放行。

Step 6:停下,确认导入模板生成(关键门禁)

汇总所有申购单的「未匹配 / 需新建」情况,列出哪几类还有未匹配行:

零件BOM:12 行未匹配(需新建)
电气件:0 行未匹配(无需导入)
紧固件:5 行未匹配(需新建)
外购件:3 行未匹配(需另行处理,由用户走「零散物料导入」skill 建码,本流程不自动导入)
零散物料:20 行(全部新建)

停下来问用户:是否生成导入模板?哪几类要生成?

> 注:外购件未匹配行不纳入本流程的导入模板——外购件=申购单,其未命中物料由用户另行用「零散物料导入」skill 建码,
> 不与零件BOM/电气/紧固件的导入模板混用。
>
> 🔁 但「金蝶确认后回填」外购件走自己的脚本:scripts/match_waibuy.py <外购件清单> --backfill [--all-sheets]
> ——不要用「零散物料导入」的 generate.py --backfill:它只认标准 14 列零散物料表,喂外购件清单会列位错乱并崩溃
> (实测 ValueError: int('6SV21008B'))。外购件清单的表结构知识只在本 skill 的 match_waibuy.py 里,回填理应由它承担。
>
> 🔀 例外:用户明确要求「把外购件未匹配行并入当前导入模板」时(2026-09-18 实践) —— 可以并,做法仍是临时中间表法:
> ① 按用户指定的「大类 + 中类」建 14 列标准零散物料临时表(1序号 2大类 3中类 4品名 5规格 6品牌 7单位 8数量 9交期 10备注 11物料编码 12电气件 13机台编号 14工程代号,编码列留空、单位统一);
> ② 跑 零散物料导入/scripts/generate.py <临时表> <物料表> --append --header-row 1 --data-start-row 2;
> ③ 临时表用完立刻走回收站清理。
> 中类由用户拍板(本例 9 行铭牌/LOGO转印贴/警示标识全归 A.002),不要自己猜;并入后仍然只出一份共用 导入模板.xlsx。
> 并入 ≠ 回填:回填照旧走 match_waibuy.py --backfill --all-sheets。

Step 7:合并生成导入模板(用户确认后)

⚠️ 共用一个 导入模板.xlsx。按用户确认的类型,合并进同一个文件。

生成模式:默认「新建部分(全新)模式」 —— 每次生成的导入文件只含本次新建的物料行,原历史数据行不带入文件(原数据在每次生成前的自动备份里,可恢复,并非丢失)。

  • 第一类用默认全新模式生成(只含该类新建部分、清除原历史、序号与分组编码从旧模板+物料表最大值接下去、生成前自动备份旧模板);
  • 其余类接 --append 并入同一文件(同属本次新建,非历史累积,不会重复传金蝶);
  • 绝对不要跨批次用 --append 累积历史数据 —— 那样会把已导入金蝶的旧物料重新带进新文件,导致重复导入。
  • 不同类别用不同系列(A/B/C),不会冲突。

> 每次真正写入前,generate.py 自动把当前 导入模板.xlsx(含全部原历史行,即「老文档」)备份到 导入模板备份/ 目录(tag 写前),写后再留一份 写后 快照。即使新文件只含新建部分,老数据也始终可恢复。

各「处理」skill 的调用方式见其各自的 SKILL.md。零散物料导入直接处理申购单(提取编码列为空的行)。

Step 8:金蝶导入 + 确认后回填

  1. 用户把合并后的 导入模板.xlsx 上传金蝶。
  2. 用户自行判断金蝶导入是否全部成功。
  3. 用户确认全部成功 → 各「处理」skill 的 --backfill 模式(或按导入模板读映射)把新编码回填进申购单空编码列。
    - 外购件 → 申购单分拣/scripts/match_waibuy.py <外购件清单.xlsx> --backfill --all-sheets
    (读共用导入模板取本次新建编码;只填空、不覆盖已有编码;回填后「匹配详情」保持「未匹配」)。
    - ✅ --backfill 现已遵守 --dry-run(2026-09-21 修复 / 2026-09-29 复核):
    4 个 generate 均把 dry_run 透传给 _shared/dedup_backfill.backfill(),其内部(if dry_run:,约 L221)
    只逐组打印「将写入 N 行」而不落盘,并有 tests/test_backfill_dry_run.py(文件逐字节不变)守护。
    → 现在可以用 --backfill --dry-run 安全预览回填。
    > 📌 历史(勿再照抄旧结论):2026-09-20 曾实测 --backfill --dry-run 仍写源文件
    > (字节数 17330 → 17338、md5 改变);该脚枪已于 2026-09-21 体检批次堵住。回填终究是写源文件的操作,
    > 保持先备份的习惯依然稳妥,但不必再因此放弃 dry-run 预览。
    - 回填后「匹配详情」列保持原值不变(如仍为「未匹配」),只填编码列 —— 属既定行为,不是漏回填。
  4. 用户指出部分失败 → 不回填(或仅回填确认成功的部分)。

🔁 换新物料表「重跑匹配」回填(2026-09-18 实践,用户常用姿势)

用户的金蝶习惯是:导入成功后重新导出一份 物料_*.xlsx 丢到桌面,然后说「新物料表,重新匹配」。
这条路径等价于回填(而且比 --backfill 更强:顺带把历史上其他漏匹配的行一起补上),做法:

  1. 先判定导入是否真成功:读新表,检查本轮新建码(各系列起止区间)是否全部存在,且表行数 ≈ 旧表 + 本轮新建数。
    两头都对 → 导入成功,可以重跑匹配;否则先问用户。
  2. 在副本上跑(不要直接在桌面文件上跑):桌面 11 份文件 copy 到工作区 _r2/work,同时留一份 _r2/bak;
    按类型分别跑 match_bom.py(零件BOM)/ match.py(紧固件,无品牌列别加 --with-brand)/ match_waibuy.py --all-sheets(外购件)。
    paths.get_material_path() 会自动取桌面最新的 物料_*.xlsx,但显式传路径更稳。
  3. 逐单元格 diff work vs bak,只看三类变化:
    - 空 → 值:新填编码 = 本轮战果;
    - 值 → 空:🔴 回归! 已有编码被清掉(默认 match_bom.py/match.py 会覆盖/清空不匹配行的旧码);
    - 值 → 新值:改写,要逐个看。
    外购件那 9 行的 未匹配 → 空 属既定行为(match_waibuy.py 命中后把「匹配详情」置空),不算丢数据。
    - ⚠️ 判回归只看「编码列」(零件BOM/ZMSH=P,紧固件=T)——只要编码列没有 值 → 空,就是安全的。
    其他列(尤其 A 序号列)的 值 → 空 / 值 → 新值 很可能是插行位移的表象:
    match_bom.py 在匹配到「新物料 + 加工件」时会补插喷塑费行 F.001.00001(本轮首次匹配时未匹配→不插,
    换新表重跑匹配成功才补插),插行后下方整段下移 + 触发序号顺延重编(见 match_bom.py 序号重编段:
    保留首条数据行原起始序号往后顺延),于是 bak 与 work 的 A 列逐行对不上。
    自检口诀:值→空 落在 A 列且同文件出现「喷塑费」新行 → 是行位移不是丢数据;只认编码列。
  4. diff 干净(无「值 → 空」落在编码列)才写回桌面;写回前 md5 比对确认一致,再走回收站清工作区。
  5. 收尾跑 audit.py <文件夹> --material <新表>,要求全 DONE、未匹配 0。

> ⚠️ 「重跑匹配」前不必加 --preserve-codes:不加才是全量重匹配(旧码被新表复核一遍,正合此意);
> 只有当用户在两次运行之间手工填过编码时才需要 --preserve-codes 保护。
> ⚠️ 喷塑费行不会重复插:match_bom.py 有「已存在则跳过」判定,可放心重跑。
> ⚠️ 模板要清:重跑匹配成功后,D:\莫佩琪\msl\导入模板.xlsx 里那批码已经导入过金蝶,
> 留着有被再次上传→重复导入的风险,需提醒用户清空(下次生成模板时「全新模式」也会覆盖它)。

物料表来源(重要:别把零散物料清单当物料表)

  • 真正的物料数据库只有金蝶导出的 物料_*.xlsx;编码*.xls / BIANMA / 副本编码 / 基础物料 /
    ERP清单·加工件 清单都是零散物料清单(预编码列表),要走「零散物料导入」skill,不能当物料表。
  • 获取顺序:classify.py --material <路径> 显式传入 → 否则自动探测桌面或 MSL_DIR 下最新 物料_*.xlsx。

> 📎 完整判定细节(含 classify.py 的金蝶管理列强约束、多份物料表如何推荐、外购件归类变更)见
> references/material-source-rules.md。

常见坑位

  • 不要自动跑导入:Step 5 必须停下确认,否则四类导入相互覆盖。
  • low / unknown 必须人工确认:分类器是基于文件名+表头特征的启发式,对命名不规范或表头异常的文件会判错。
  • 零散物料无匹配 skill:它本身就是「未编码行全部新建」,所以直接从 Step 5 进导入。
  • .xls 不支持原地改:先提示用户另存为 .xlsx,再跑匹配。
  • 未匹配别急着建新码:紧固件常把强度等级(如 8.8级)误填进材质列导致 0 命中,先核对,勿据此造重复物料。

高频坑(每条 = 一句话现象 + 自检口诀;完整复盘见 references/incidents.md)

  • 🔴 紧固件四字段 0 命中的第二种根因:物料库把材质/表面处理语境写进了「名称」字段(2026-09-19)
    自检口诀:紧固件 dry-run 报 0/N(N 远大于 0)→ 先看物料库名称是否内嵌材质/表面处理语境。
  • 「焊接」文件名会误导零件BOM:焊接设备采购单(表头含大类/中类/单位,实为电气件)会被"焊接"关键词带偏。分类器已对「设备/采购单」优先判电气,但"焊接追加申购单"这类表头像电气件的仍会标 low 冲突请你确认,别直接信文件名。
  • 🔴 零件BOM 喷塑费行「批次」会被表头纵向合并泄漏(2026-09-17,match_bom ≥1.9.13 已修)
    自检口诀:喷塑费行 B 列(区域/批次列)出现「区域/批次」等表头词 → 表头合并泄漏。
  • 🔴 零件BOM「修改版」新增 C16 列会挤走编码列(2026-09-14,match_bom ≥1.9.12 已修)
    自检口诀:dry-run 显示 STANDARD(Col16) 但 C16 表头既不是空也不是「物料编码」→ 立刻查会不会覆盖数据。
  • 🔴 同图号「表面处理措辞差异」会造成重复建码(2026-09-14)
    自检口诀:生成新码前按「规格型号」反查物料库——同规格已有码就先问是不是措辞差异。
  • 同名申购单桌面 vs msl 归档可能不是同一版:判断"是否已处理过"不能只看文件名,要比对明细行与列结构;重跑前先备份(match_bom.py 不自动 .bak)。
  • 外购件清单 = 申购单(不是零散物料):外购件清单由本 skill 的 scripts/match_waibuy.py 处理(匹配名称+规格+品牌);零散物料走「零散物料导入」skill,两者不混放同一分拣文件夹。
  • 🔴 外购件清单「回填」必须用 match_waibuy.py --backfill,不能用零散物料导入的 generate.py --backfill(2026-09-14)
    自检口诀:回填外购件报 int() 或列位对不上 → 用错脚本了。
  • 🔴 多页外购件清单的「页脚行」曾被误标「未匹配」(2026-09-14 已修)
    自检口诀:外购件 未匹配 条数比实际缺码行多 → 看有没有页脚行混进了统计。
  • 外购件清单的「品牌」列常写的是淘宝链接:品牌会被归一成「淘宝」,回填时「名称+规格+品牌」精确键对不上。--backfill 因此设计了「名称+规格」兜底(仅当该键唯一才采用;多条候选则跳过告警,绝不猜)。
  • 🔴 外购件清单末尾的「公司名整幅合并行」曾被误标「未匹配」(2026-09-16,match_waibuy ≥1.3.0 已修)
    自检口诀:外购件「未匹配」数比人工数的缺码行多 1 → 看最后一行是不是公司名横幅。
  • 🔴 物料表重复脏数据全量打印会淹没匹配结果(2026-09-16 已修)
    自检口诀:匹配输出出现十万字符级刷屏 → 看是否把重复组全量列出了。
  • 🔴 多 sheet 申购单的回填会跨表串写(按行号写错表,覆盖正确编码)(2026-09-16,dedup_backfill ≥1.2.0 已修)
    自检口诀:回填日志必须出现全部 sheet 名(只出现一个就说明其余页没走对分支);回填后必做「编码→物料表反查名称」逐行校验(串写不报错、日志还显示"成功")。
  • 🔴 多 sheet 申购单:匹配与复核必须「双管齐下」(2026-09-16 实测漏一页)
    自检口诀:文件名带「采购单/清单」但只有几十行、页脚写「第 1 页 共 2 页」→ 先查 sheetnames,别只跑活动表。
  • 🔴 audit 的 PARTIAL_EMPTY 报数对不上时先查「表头行是否取错」(2026-09-16 实测误报 11 行)
    自检口诀:audit 报 PARTIAL_EMPTY 但与人工数的缺码行对不上 → 看表头行取的是第几行。
  • 同名文件多份只计一次:同一文件在多个目录出现时,校验脚本会去重(只计一次)并报告所有重复路径,避免重复计数。
  • 紧固件处理 skill 目录名已统一为「紧固件处理」:目录名与显示名一致;运行其脚本用 紧固件处理/scripts/... 路径。
  • 🔴 文件名弱词「设备」会把紧固件抢成电气件(2026-09-18,classify ≥1.5.0 已修)
    自检口诀:文件名同时出现「设备」和「紧固/螺丝/螺栓」→ 必须判紧固件,「设备」不算弱证据。
  • 🔴 申购单可能附带「历史草稿」工作表(2026-09-18)
    自检口诀:数据行数对不上 max_row → 先查 sheetnames 有没有草稿/废弃页;有草稿表就别加 --all-sheets。
  • 🔴 零件BOM「无区域/批次列」变体(2026-09-18)
    自检口诀:dry-run 里「表头认列 XX 自动修正」= 变体适配生效,属正常,无需手工加 --surface-col。
  • 🔴 外购件匹配对「已填编码」幂等保留 → 换新物料表「重跑」不会刷新已填行(2026-09-12)
    自检口诀:重跑后「命中 0 / 保留 N」且期望有变化 → 目标行被幂等保护锁住了,须先清空该行编码再跑。
  • ✅ 多 sheet 外购件清单的 audit 覆盖已修(2026-09-16 起):audit.py ≥v1.4 已遍历全部 sheet。⚠️ 但匹配阶段仍需 --all-sheets(默认只处理活动表,不加会打印 ⚠️ 提示)。

维护与回归测试

本 skill 的分类器与表尾识别已纳入仓库级回归测试(<skills_dir>/tests/),改动后必跑:

cd ~/.workbuddy/skills
PYTHONIOENCODING=utf-8 python -m pytest tests -q

与本次直接相关的两组:

测试 守护
tests/test_classify_rules.py classify.py 的 score_type() 判定 —— 含「misc 词条误吞零件BOM/电气件/紧固件」(2026-08-14 修复项)、金蝶物料表与零散清单的区分、标题强信号
tests/test_waibuy_tail_rows.py match_waibuy.py 的表尾行识别 —— 页码页脚、A:M 公司名横幅、表尾关键词、5 列阈值边界

另有三项跨 skill 门禁,改版本号或改 _shared/ 后必查:

测试 守护
tests/test_version_drift.py SKILL.md version == 主脚本 __version__,且同 skill 内所有脚本版本一致
tests/test_shared_in_sync.py 5 份 in-skill _shared/ 与母本逐字节一致(改完先跑 python sync_shared.py)
tests/test_pyflakes_clean.py 全部 scripts/ + 母本 _shared/ 零 pyflakes 告警
tests/test_multisheet.py 4 个匹配脚本的多 sheet 口径一致(默认只跑第一张表但必打 ⚠️ 警告、--all-sheets、--sheet 定向)
tests/test_doc_references.py 每个 references/*.md 都被 SKILL.md 引用(防孤儿参考);incidents.md 存在且被索引

> 📁 事故复盘已归档:本文档「常见坑位」只留「现象 + 自检口诀」,
> 完整根因与修复过程见 references/incidents.md(按日期分节,可搜关键词)。

> ⚠️ 升版本号时别只改主脚本:申购单分拣 的 classify.py/audit.py/match_waibuy.py
> 三脚本版本必须一起升(1.4.0 起统一),否则 test_version_drift 直接失败。
> 详见 tests/README.md 的完整清单与维护注意事项。

常见问题

5 问
答案由本站依据条目字段整理
申购单文件夹自动分拣与调度怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_d201725d/requisition-dispatcher。安装方式为未标注。装完刷新技能列表或重开客户端。

申购单文件夹自动分拣与调度支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

申购单文件夹自动分拣与调度权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

申购单文件夹自动分拣与调度收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

申购单文件夹自动分拣与调度用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。