下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/org-b02a8cf7--erp-stock-query.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @org-b02a8cf7/erp-stock-query。ERP 库存查询
阅读全文 (展开查看完整说明)
概述
ERP 库存查询(接口方式)
安全与合规声明
逐条对应常见的安全排查项:
- 只读:所有取数请求固定
type=read,不调用任何写接口,不建单、不改单、不保存数据。 - 无内置凭据:技能包内不含任何账号、密码、Token、默认地址或租户标识。四项登录信息全部由使用者在使用时提供。
- 凭据不落盘:脚本不写 Cookie 或密码到磁盘,不把密码写进任何输出文件,不在日志中打印密码;
报表「查询概要」页默认不写入 ERP 地址与登录账号(需显式加 --include-source-info 才会写)。
- 输出最小化:对使用者只输出「产品编号」与「可开单库存量(业务单位)」两列。
品牌、系列、仓库、批号、规格、价格、成本、实物库存等内部字段虽然会随接口返回,但在本地筛选完成后即被丢弃 —— 不写进结果文件、不打印、不进报表。
- 无外呼:除使用者显式指定的 ERP 地址外,不与任何第三方服务通信;无遥测、无埋点、无回传。
- 不下载远程脚本:所有逻辑都在包内脚本里,运行期不从网络拉取或执行任何代码。
- 依赖最小:仅
requests+openpyxl,无其他第三方包。 - 权限最小:仅需
Bash与Read。
定位与边界
- 做什么:向使用者取登录信息 → 接口登录 → 按功能号查询库存 → 过滤 → 只输出
「产品编号 + 可开单库存量(业务单位)」两列 → 生成 Excel 清单。
- 不做什么:不建单、不改单、不保存任何数据(纯
type=read只读取数)。 - 输出边界(硬性):对使用者只开放两个字段 —— 产品编号、可开单库存量(业务单位)。
取数时仍会拉回完整数据行(否则无法做本地区间筛选、也无法定位产品),但白名单之外的字段在落盘与打印之前一律被裁掉:报表里不会出现品牌、系列、仓库、批号、规格、价格、成本、实物库存等任何其他列。需要扩列时用 --fields,那属于内部核对用途,不要对使用者开放。
- 适用功能:默认
1800 仓库即时库存;同族库存功能只要换--func功能号即可(先用--describe探字段)。
换功能号后若字段名不同,脚本会提示「该功能的显示字段里没有 matname / freestock」。
- 适用使用者:同一款 ERP 在不同企业是各自独立部署的,本技能按「一套流程、多家使用」设计,
使用者可能是陶瓷、瓷砖、建材等行业的厂家或经销商,每个人用自己的地址、自己的账套。
- 发布方声明:本技能由「携简」发布并维护,面向携简 / victop 系 ERP 的通用接口取数场景;
文中的产品名仅用于说明适用对象,方便使用者搜索识别。使用者需自行确保已获得对目标 ERP 实例的合法访问授权,并自行承担因部署版本差异导致的接口不兼容风险。
前置:登录信息一律向使用者索取
技能包不含任何默认值,因为它服务的是多家企业各自的部署。启动任何取数前,先拿到这四项:
| 项 | 说明 | 传参 | 环境变量 |
|---|---|---|---|
| ERP 地址 | 形如 http://主机:端口。使用者可能只给域名/IP,或直接粘浏览器里的登录页地址,脚本会自动归一化 | --host | XJ_ERP_HOST |
| 登录账号 | ERP 的用户名(usercode),通常就是对方日常登录用的那个 | --user | XJ_ERP_USER |
| 登录密码 | 明文即可,脚本自行做 MD5。不要回显、不要写入任何文件 | --pwd | XJ_ERP_PWD |
| 公司代码 | 数字型。同一地址下可能有多个账套,经销商通常只知道自己的那一个 | --companyid | XJ_ERP_COMPANYID |
取值优先级:命令行参数 > 环境变量 > --ask 交互询问。四项缺任意一项,脚本都会打印MISSING=... 加一份中文索取清单,并以退出码 2 结束——绝不使用兜底值。
怎么问(可直接照这段话术发给使用者)
为了帮你查库存,需要你提供 4 项你自己企业的 ERP 信息:
- ERP 地址——浏览器里登录页的网址直接发我就行
- 登录账号
- 登录密码
- 公司代码——数字,在 ERP 的「用户信息」里能看到
这些信息只在本次查询中使用,我不会写进任何文件,也不会替你保存。
交互规则(AI 执行时遵守)
- 一次问全:四项一起问,不要挤牙膏式的一项一项要。使用者只给了一部分时,只追问缺的那几项。
- 本次对话内已给过就直接复用,不要重复询问。但换企业、换账号时必须重新确认,
不要把上一家的地址或凭据套到这一家身上。
- 不知道就问,不要猜:不要用「上次那个地址应该是……」「公司代码一般是 1001」这类假设。
猜错地址会连到别人家的系统,这既是事故也是安全问题。
- 密码不回显:拿到后优先用环境变量前缀的形式传参,而不是
--pwd出现在参数列表里:
XJ_ERP_HOST='http://<地址>' XJ_ERP_USER='<账号>' XJ_ERP_PWD='<密码>'
XJ_ERP_COMPANYID='<公司代码>' python scripts/erp_stock_query.py --func 1800 --filter "..."回复使用者时不要复述密码,也不要把它贴回聊天里确认。
- 不写盘:不要把凭据写进技能目录、记忆文件、配置或任何脚本。凭据只存在于当次对话与当次进程环境里。
- 看到
MISSING=就去问:脚本打出MISSING=host,user,pwd,companyid就是明确信号——
该向使用者索取了。不要重试脚本、不要空跑、不要自己编一个值。
地址容错
使用者的输入可能五花八门,脚本会自动归一化成 scheme://host[:port]:
| 使用者给的形式 | 归一化结果 |
|---|---|
erp.example.com:8182 | http://erp.example.com:8182 |
http://erp.example.com:8182/apps/erp/login.do | http://erp.example.com:8182 |
https://erp.example.com/ | https://erp.example.com |
若某企业把 ERP 部署在非默认上下文路径下,用 --login-path / --erp-base 覆盖(详见 references/erp-api.md)。
铁律(先读这五条)
- 走 HTTP 接口,不要走网页 / GUI 路线。 本技能按无图形界面环境设计;在服务器、容器、沙箱等环境下驱动真实浏览器往往直接失败(进程能起、页面随即被关闭)。所有操作必须走接口。
- 登录信息由使用者提供,严禁写进技能或脚本。 运行时通过环境变量 / 参数传入,或
--ask交互输入。这既是安全要求,也是上架审核的检查项。 - 一企一凭据,不要串用。 同一个使用者在多家企业之间切换时,每次都重新确认是哪一家;不要缓存跨企业的地址或账号。
- 会话只有几分钟。 登录与取数必须在同一次脚本执行内完成,不要「先登录存 Cookie,过一会儿再取数」。
- 只读。 不碰任何写接口。取数结果落本地文件后,后续分析与出报表都读本地文件,不要为了同一份数据反复登录取数(会话短,且浪费)。
标准工作流
第 0 步:向使用者取四项登录信息
按上面的「交互规则」问齐 ERP 地址 + 账号 + 密码 + 公司代码。不要尝试网页登录、也不要让使用者去某个页面手工录入。本机人工手跑时,也可以用 --ask 让脚本逐项问(密码不回显):
python scripts/erp_stock_query.py --ask --func 1800 --describe第 1 步:先探字段(换功能号或换企业时必做)
XJ_ERP_HOST='<地址>' XJ_ERP_USER='<账号>' XJ_ERP_PWD='<密码>' XJ_ERP_COMPANYID='<公司代码>'
python scripts/erp_stock_query.py --func 1800 --describe输出该功能的「查询条件(head.fields)」与「显示字段(body.fields)」清单 —— 这是从使用者自己的 ERP 动态获取字段字典的官方途径,也是本技能不内置任何字段字典的原因。拿到清单后再决定过滤条件怎么写。
⚠
--describe的输出是功能元数据(用于确认功能与字段是否可用),不是查询结果。它是给执行者看的,不要整份贴给使用者,也不要把它当作库存信息交付。
字段命名规律与常见列名见 references/field-conventions.md。换了企业一定要重跑这一步:自定义字段(CV 系列)各家不同。
第 2 步:取数
export XJ_ERP_HOST='<地址>' XJ_ERP_USER='<账号>' XJ_ERP_PWD='<密码>' XJ_ERP_COMPANYID='<公司代码>'
# 按产品编号查(产品编号常为后缀形态,务必用 like,脚本默认即 like)
python scripts/erp_stock_query.py --func 1800 --filter "产品编号=<编号>" --outdir ./erp_stock_out
# 多条件叠加(AND 关系,--filter 可重复)
python scripts/erp_stock_query.py --filter "仓库编号=<仓库>" --filter "品牌=<品牌>"
--filter "规格=<规格>" --outdir ./erp_stock_out
# 数值区间(自动走本地精确筛选,服务端会忽略区间条件)
python scripts/erp_stock_query.py --filter "可开单库存>1000" --outdir ./erp_stock_out
# 全量(不加条件)
python scripts/erp_stock_query.py --outdir ./erp_stock_out
# 直接写原始 cfilter(实体列名 + 运算符)
python scripts/erp_stock_query.py --filter-json '{"matname":{"like":"<编号>"}}' --outdir ./erp_stock_out
# 条件写法不确定时,加 --probe:先带条件查,无结果则全量拉回本地筛选
python scripts/erp_stock_query.py --filter "产品编号=<编号>" --probe --outdir ./erp_stock_out产出 <outdir>/result_<func>.json。它的 rows 只有两列 —— matname(产品编号)与 freestock(可开单库存量 / 业务单位);meta.fields_exposed 记录本次开放了哪些列。日常取数不再生成 config_<formid>.json(只有 --describe 时才落盘)。
中间文件
result_*.json的meta.usercode会记录本次登录账号(便于核对是哪家账套取的数据)。该文件用于本地分析,对外发送前请先确认是否需要删除或脱敏。
白名单之外的字段在落盘前已被丢弃,所以:
- 不要试图从
result_*.json里找品牌、仓库、批号、价格等字段 —— 它们不在文件里; - 需要按这些维度筛选,照常用
--filter(筛选发生在裁剪之前,不受影响)。
第 3 步:生成库存清单
python scripts/erp_stock_report.py --input ./erp_stock_out/result_1800.json
--out ./kb/库存清单.xlsx --title "库存查询"产出 2 个 Sheet:查询概要 + 库存清单。
库存清单 只有两列 —— 产品编号、可开单库存量(业务单位),末行为合计;品牌 / 系列 / 仓库 / 批号 / 规格 / 价格等一律不进报表。查询概要 页默认对 ERP 地址与登录账号做脱敏;确实需要写入时加 --include-source-info。
第 4 步:回读校验并交付
生成后必须用 openpyxl 回读一次,核对:
- Sheet 名称与数量应为
查询概要、库存清单; 库存清单表头只有两列,且为「产品编号」「可开单库存量(业务单位)」;- 明细行数 == 取数行数;
- 末行合计 == 各行可开单库存量之和。
确认无误再把 xlsx 路径给使用者。
多企业(多租户)使用注意
| 场景 | 做法 |
|---|---|
| 同一次对话里只服务一家 | 四项信息问一次即可,后续取数直接复用 |
| 使用者中途说「换一家公司」 | 重新问齐四项,不要沿用上一家的地址/账号;换企业后必须重跑 --describe |
| 同一地址下多个账套 | 公司代码不同 → 同一个地址、不同账号或不同 --companyid,结果完全不互通 |
| 登录失败 | 提示使用者核对这一家的四项信息是否匹配;不要改用其他企业的凭据重试 |
| 在云端沙箱里连不上 | 企业 ERP 多为内网或白名单访问,云上环境可能被网络策略阻断 → 改在能访问该地址的环境执行 |
| 不同企业的可开单字段名可能不同 | 输出字段固定为 matname / freestock。若某部署字段名不同,脚本会提示「该功能的显示字段里没有 […]」→ 用 --describe 核对后再定 |
| 使用者想要带品牌/仓库列的报表 | 本技能只输出两列(产品编号、可开单库存量(业务单位))。可以按品牌/仓库筛选,但报表不会带出这些列 |
过滤条件速查
--filter "中文名=值" 支持的中文名(→ 实际传给接口的实体列名):
| 中文名 | 列名 | 中文名 | 列名 |
|---|---|---|---|
| 产品编号 | matname | 色号 | cv2 |
| 等级编号 | matcode | 颜色 | colortype |
| 仓库编号 | stcode | 包装码 | cv1 |
| 仓库名称 | stname | 批号 | batchcode |
| 品牌 | brand | 规格 | special |
| 系列 | matgroupname | 工厂编号 | gccode |
| 产品名称 | xilie | 公司代码 | companyid |
| 等级 | gradename |
- 默认运算符
like(包含匹配)。不要用equal查产品编号 —— 产品编号常为后缀形态(前缀是品牌/工厂码,同一编号会以多个前缀出现),equal会一条都查不到。 - 多条件之间是 AND。
- 数值 / 日期区间条件一律走本地筛选:这类区间运算符(
gt/ge/lt/le以及头部的库存区间、入仓日期区间条件)在部分部署下会被服务端静默忽略——不报错,直接返回全量。所以直接写--filter "可开单库存>1000"即可,脚本会自动拉全量后本地精确筛选。 - 筛选口径与输出口径一致:
可开单库存筛的是业务单位(箱 / 片 / 个)的数字,也就是报表里那一列,两者可以直接对照;要用基本单位口径筛,写可开单库存(基本单位)>1000。 - 其余数值中文名
实物库存/开单未提量/留货量/在途量/滞留天数/可开单平方仍按基本单位或 ㎡ 计算 —— 它们只用于筛选,不会出现在输出里。 - 筛选维度可以比输出字段更宽:按品牌、仓库、批号、规格等筛选都支持,筛选发生在字段裁剪之前,只是这些列不会进结果文件与报表。
- 上表的字段映射在 victop 系 ERP 中通用,但不同部署的自定义字段(CV 系列)会有差异,换环境时请先
--describe核对。
输出与汇报规范
- 对使用者只给两个字段:产品编号、可开单库存量(业务单位)。
报表里没有第三列;聊天回复里同样不要附带品牌、系列、仓库、批号、规格、价格、成本、实物库存、占用量等任何其他字段 —— 这是本技能的输出约定,不是可选项。
- 报表落
kb/(或使用者指定目录),命名{功能号}库存清单.xlsx,2 个 Sheet(查询概要+库存清单)。 - 数量口径是业务单位(箱 / 片 / 个),不换算、不与基本单位混加、不给平方数。
- 聊天回复只给摘要:取数时间、是哪家企业/地址、过滤条件、命中行数、产品编号数、
可开单库存量合计;需要明细时给 xlsx 路径。
- 回复中不要出现密码;账号与地址按需表述,不必逐字复述。
- 用中文、结构化表格呈现。
常见坑
| 现象 | 原因与解法 |
|---|---|
脚本打印 MISSING=host,user,pwd,companyid 并退出码 2 | 缺登录信息。照清单向使用者要,不要重试、不要编值 |
报 列名 '<x>_h' 无效 | 头部字段名带 _h 后缀,但过滤必须用去掉 _h 的实体列名(如 matname)。脚本的 FIELD_MAP 已自动转换 |
| 响应不是 JSON、开头像 HTML | 会话失效。重跑脚本(登录 + 取数一次完成) |
| 登录失败 code 非 1 | 四项信息与目标企业不匹配:核对地址/账号/密码/公司代码,尤其别把 A 家的账号配 B 家的地址 |
| 连接被拒绝 / 超时 | 该 ERP 地址从当前环境不可达(内网、白名单或云沙箱网络策略)。换到能访问该地址的环境执行 |
报 对象名 '<x>_atom' 无效 | 用了 getAlldata.action。部分部署该接口不可用,必须用 runProject |
| 查产品编号结果为空 | 误用了 equal。改用 like(脚本默认),或加 --probe |
| 加了区间条件却返回全量 | 服务端静默忽略区间运算符。改用脚本的本地筛选(写 --filter "可开单库存>1000" 即自动生效) |
筛选 >1000 与看到的数字对不上 | 筛选默认按业务单位口径(与输出一致);要按基本单位筛就写 可开单库存(基本单位)>1000 |
| 日志提示「功能 X 的显示字段里没有 ['freestock']」 | 换了功能号,该功能没有这个字段名。用 --describe 核对该功能实际的字段名 |
| 结果文件里找不到品牌/仓库/价格 | 正常。白名单外的字段已按输出约定丢弃,不落盘 |
erp_stock_out/ 下没有 config_*.json | 正常。日常取数不再落盘功能配置,只有 --describe 时才生成 |
| 报表里想加一列 | 本技能只输出两列。确实要扩列用 --fields,但那属内部核对用途,交付给使用者时仍应只给两列 |
参考文件
references/erp-api.md—— 接口协议细节:登录表单、runProject参数、formid 命名规则、配置接口、响应结构、字段命名规律,以及--login-path/--erp-base的用法。references/field-conventions.md—— 字段命名规律、单位三套口径、常见列名词表,以及「如何用--describe从自己的 ERP 动态取字段字典」。
上架元数据说明
本技能的 frontmatter 同时包含两套发布通道所需字段,便于一次打包、两处上架:
| 字段 | 用途 |
|---|---|
name / display_name / display_name_en / description_zh / description_en / category / author / allowed-tools | WorkBuddy 开放平台解析所需 |
slug / displayName / summary / tags | SkillHub 校验所需(slug 为 kebab-case 唯一标识,version 为 SemVer) |
description / version / license | 两个通道共用 |
author 与 license 按发布方的实际情况填写;如需声明开源许可,请在提交前替换 license 的值。
依赖
Python 3 + requests + openpyxl。