企享云自然语言开票 Skill
本 Skill 用于自然语言开票闭环:解析用户开票需求,先登录获取销方企业,再用云抬头补齐购方,结合商品和金额字段生成草稿与确认摘要;只有用户明确确认后才调用真实开票 MCP。不要直接改 /Users/xueds/Python/mcpservice,该项目只作为 MCP 工具定义来源。
前置条件:凭证配置
本 Skill 依赖企享云开放平台凭证:
client_appkeyclient_secret
API 密钥申请:https://open.qixiangyun.com
凭证读取优先级:
- Skill 根目录的
.env - Skills 公共父目录的
.env(/Users/xueds/Python/skills/qixiangyun-skill/.env) - 系统环境变量
QXY_CLIENT_APPKEY/QXY_CLIENT_SECRET
首次使用时,如果凭证不存在:
- 询问用户的
client_appkey和client_secret - 如果用户没有凭证,提示:
appKey和appSecret请注册企享云开放平台申请 https://open.qixiangyun.com - 在 Skill 根目录或公共父目录创建
.env:QXY_CLIENT_APPKEY=用户提供的appkey QXY_CLIENT_SECRET=用户提供的secret - 后续调用由脚本自动读取,无需再次询问
税局登录强关联
开票流程内嵌税局登录,不要求用户单独调用登录 Skill。自然人登录密码必须由用户在本机通过环境变量传入,避免进入对话、命令历史或日志。禁止要求用户把税局密码直接发到对话中,也禁止在回复中复述密码:
export QXY_LOGIN_PASSWORD="your_password"
先登录并缓存企业税局登录态:
python3 scripts/invoice_issuance_workflow.py login \
--login-area-code 3100 \
--login-phone 13800138000 \
--login-password-env QXY_LOGIN_PASSWORD \
--login-nsrsbh 销方税号
也可以在 draft 命令中携带同样的登录参数。脚本会先完成自然人登录、企业选择、企业订购、多账号创建、企业登录或快速登录态校验;登录成功后自动把 nsrmc/nsrsbh/accountId/aggOrgId 注入开票草稿,作为销方与开票账号字段。
缺少有效登录态时,必须先返回 tax_login 卡点并引导用户提供登录地区代码、自然人手机号,以及在本机设置 QXY_LOGIN_PASSWORD。此阶段不要同时要求用户配置 invoice_profiles.json、税收编码或税率。每次生成新的开票草稿都必须获取或读取企业列表并展示给用户确认本次开票销方;即使列表只有一个企业、已经存在 selectedEnterprise、企业登录态仍有效,也不得跳过本次确认。只有当前续跑请求明确传入 --enterprise-index、--login-nsrmc 或 --login-nsrsbh 时才可继续。取得选中企业的 nsrsbh/aggOrgId 后再进入智能赋码。不要先向用户索要销方地址、电话、开户行、银行账号、复核人或收款人;这些不是生成草稿的前置硬条件。
登录等待用户输入时,返回 waiting_for_user_input=true 和 user_input_kind:
enterprise_selector:每次开票都返回自然人账号关联的企业列表;用户确认后补充--enterprise-index、--login-nsrmc或--login-nsrsbh续跑。单企业和有效缓存场景也不能跳过。natural_sms_code:补充--natural-sms-code续跑。enterprise_sms_code:补充--enterprise-sms-code续跑。tax_login_credentials:登录地区、手机号或密码环境变量不完整;引导用户在本机设置密码环境变量后续跑,不接收明文密码。
本地 enterpriseLogin.verified=true 只表示历史流程走到企业登录完成,不能替代本次开票的企业确认。用户确认企业后,才通过 login_enterprise_account 校验并复用缓存;校验不 ready 时,保留订购和多账号信息,清理企业登录态并重新触发企业短信登录。
可选开票档案
invoice_profiles.json 不是生成草稿的必需条件。自然语言开票优先通过税局登录获取销方;本地档案只用于缓存常用商品、税收编码、税率、购方别名,以及离线测试场景。没有商品档案时,登录成功后必须使用 invoice_classification MCP 查询,不得要求用户先创建配置文件,也不得由模型编造商品编码。脚本按以下优先级读取可选档案:
- Skill 根目录:
qixiangyun-skill/invoice/qixiangyun-invoice-issuance-skill/invoice_profiles.json - 公共父目录:
/Users/xueds/Python/skills/qixiangyun-skill/invoice_profiles.json - 环境变量
QXY_INVOICE_PROFILE_FILE指定的文件
推荐配置结构。default_seller 是兼容字段,不是正常开票前置;真实开票时优先使用登录返回的企业和账号字段:
{
"default_invoice_type": "普票",
"default_seller": {
"nsrsbh": "销方纳税人识别号",
"name": "销方企业名称",
"address": "销方地址",
"phone": "销方电话",
"bank": "开户行",
"bank_account": "银行账号",
"reviewer": "复核人",
"payee": "收款人",
"accountId": "可选账户ID",
"aggOrgId": "可选聚合机构ID"
},
"default_product": {
"name": "信息技术服务",
"tax_code": "3040203000000000000",
"tax_name": "信息系统服务",
"tax_rate": "0.06",
"unit": "项"
},
"buyers": [
{
"alias": "腾讯",
"name": "深圳市腾讯计算机系统有限公司",
"taxNumber": "91440300708461136T"
}
]
}
缺少销方时,返回 tax_login 卡点并只处理登录。登录完成后,缺少商品编码时自动使用 invoice_classification 服务的 query_invoice_tax_classification_auto 查询,参数包含登录获得的 nsrsbh、aggOrgId、可选 accountId 和商品名称 xmmc。唯一完整候选可用于草稿;存在多个候选时必须展示编码、名称、税率和单位让用户确认,不得自动选择。无可用结果时,引导用户确认商品名称或手工补充编码、名称、税率和单位。购方信息优先走 invoice_title 云抬头查询补全,只有多候选或专票缺购方税号时才追问用户。
主流程:自然语言开票
flowchart TD
A["用户输入:给 XXX 开 XXX 票"] --> B["AI 解析开票信息:客户、商品、金额、票种"]
B --> C{"是否有有效税局登录态?"}
C -- "否" --> D["引导本机设置密码环境变量并完成登录"]
D --> D1["获取并展示自然人关联企业列表"]
D1 --> D2["用户确认本次开票销方企业"]
D2 --> E["获取销方 nsrsbh/accountId/aggOrgId"]
C -- "是且企业已确认" --> E
E --> F["云抬头补购方;缺商品档案时调用智能赋码"]
F --> F1{"赋码候选是否唯一?"}
F1 -- "否" --> F2["展示候选并让用户确认"]
F1 -- "是" --> G1["校验金额、票种、购方税号、开票额度"]
F2 --> G1
G1 --> G{"是否通过校验?"}
G -- "否" --> H["返回错误或风险下一步"]
G -- "是" --> I["生成确认摘要,等待用户确认"]
I --> J["提交 issue_blue_invoice_auto"]
J --> K{"是否需要扫脸?"}
K -- "是" --> L["调用 face-qr 返回税务 APP 二维码"]
L --> M["用户扫码"]
M --> N["resume-after-face 查询状态并继续提交"]
K -- "否" --> O{"开票是否成功?"}
N --> O
O -- "否" --> P["返回失败原因或异步状态"]
O -- "是" --> Q["输出发票号码、日期、PDF/OFD/XML"]
1. 生成草稿
python3 scripts/invoice_issuance_workflow.py draft \
--text "给腾讯开软件服务费1000元,价税合计"
如果用户只说“开 1000 元发票”,金额口径不明确,必须追问“价税合计还是不含税金额”。可在用户确认后传:
python3 scripts/invoice_issuance_workflow.py draft \
--text "给腾讯开软件服务费1000元" \
--amount-mode total
draft 返回:
waiting_for_user_input=true:包含missing_fields、question、draft_idwaiting_for_user_input=false:包含confirmation_summary、payload_preview、draft_id
草稿生成时会调用销方企业信息和开票额度 MCP 校验;认证失败、登录态异常、业务失败、额度不足或税局不稳定时,脚本会返回 waiting_for_user_input=true 并给出下一步,不会改用其他通道。只做本地草稿演练时可设置 QXY_INVOICE_SKIP_PREFLIGHT=1 跳过预检。
2. 确认并开票
真实开票前必须把 confirmation_summary 复述给用户,并得到明确确认。
python3 scripts/invoice_issuance_workflow.py issue \
--draft-id 草稿ID \
--confirmed "确认开票"
确认文本为空或不包含“确认/同意/可以开票”等明确意图时,脚本只返回草稿预览,不调用开票 MCP。
如果开票 MCP 返回 720007、扫脸或人脸认证提示,脚本会自动调用 face 服务获取二维码,并返回:
face.tax_app.rzid/face.tax_app.qrcode:电子税务局 APP 扫脸认证face.national_id_app.rzid/face.national_id_app.qrcode:国家网络身份认证 APP 扫脸认证face.*.image_path:Skill 使用内置纯 Python 实现生成的本地 PNG 绝对路径,兼容 Windows、Linux 和 macOS,无需安装qrcode、Pillow 或系统二维码工具face.*.media_directive/face.openclaw_media:OpenClaw 可识别的图片输出标记
在 OpenClaw 对话中,拿到 media_directive 后必须将其原样放在回复的独立一行。回复第一行提示用户使用税务 APP 扫码,第二行直接输出类似 MEDIA:/绝对路径/face_qr/tax-app-RZ001.png 的标记。
MEDIA: 行不能放进代码块,也不要把 qrcode、gwEwm 或 Base64 原文直接展示给用户;这些字段是二维码内容,不是 OpenClaw 可渲染的图片。
人脸工具和发票查询工具必须携带与开票草稿一致的 accountId/aggOrgId 上下文。优先通过 --draft-id 让脚本自动读取草稿中的账号字段;不要只传 nsrsbh,否则容易出现 720016 登录信息有误。
扫码后可单独查询状态:
python3 scripts/invoice_issuance_workflow.py face-status \
--nsrsbh 销方纳税人识别号 \
--rzid face返回的rzid \
--draft-id 草稿ID
slzt=1 表示未扫脸,slzt=2 表示扫脸成功,slzt=3 表示二维码过期。按完整链路续跑时使用 resume-after-face:脚本会先查询扫脸状态,成功后自动继续提交同一草稿;未扫脸或二维码过期时不会提交开票。
python3 scripts/invoice_issuance_workflow.py resume-after-face \
--draft-id 草稿ID \
--nsrsbh 销方纳税人识别号 \
--rzid face返回的rzid \
--confirmed "确认开票"
二维码过期时重新获取二维码:
python3 scripts/invoice_issuance_workflow.py face-qr \
--nsrsbh 销方纳税人识别号 \
--kpyxm 开票人姓名 \
--draft-id 草稿ID
3. 查询开票结果
异步处理、扫脸后续跑或用户要求“查询开票结果”时,优先使用 workflow 的草稿查询命令:
python3 scripts/invoice_issuance_workflow.py query-result \
--draft-id 草稿ID
该命令会从草稿 payload 自动读取 nsrsbh、ly_ddbh、accountId、aggOrgId,默认调用 query_invoice_details_auto 查询同一来源订单的发票明细。不要让用户手动执行裸 mcp_client.py --tool query_invoice_list_auto ... 后再人工补 accountId/aggOrgId;这会破坏开票上下文,容易触发 720016 登录信息有误。
需要按日期范围查列表时才使用:
python3 scripts/invoice_issuance_workflow.py query-result \
--draft-id 草稿ID \
--mode list \
--kprqq 2026-06-04 \
--kprqz 2026-06-04
query-result 只有查到 invoice_number、issue_date 或 pdf_url/ofd_url/xml_url 时才返回 issued=true;仅返回 2000 成功码但没有发票号码或版式文件时,仍按“处理中/未查到结果”处理。
4. 输出结果
开票成功时返回:
invoice_numberinvoice_codeissue_datepdf_url/ofd_url/xml_urlmcp_raw_summary
如果 MCP 返回扫脸、登录态、额度不足、购方异常、税局不稳定或异步处理中,脚本会停止流程并返回结构化下一步,不能切换到旧登录链路或手写 HTTP。2001 或“处理中”只表示开票进入异步处理,不能对用户表述为“发票已提交成功”或“开票成功”;只有拿到发票号码、开票日期或 PDF/OFD/XML 链接后,才算开票成功。
业务规则
- 用户未明确金额口径时,必须追问“价税合计”还是“不含税金额”。
- 普票允许购方税号为空,但确认摘要必须展示“购方税号为空”。
- 专票必须有购方税号;缺失时不得提交。
- 商品/服务缺失时优先使用
default_product;没有配置时必须追问,不得编造商品编码。 - 开票、红冲都属于高风险动作,调用真实 MCP 前必须二次确认。
- 不在回复和日志中输出
client_secret、完整 API 凭证、验证码或完整私密业务 payload。 .env、invoice_profiles.json、.generated/运行态草稿不应提交到版本控制。
原子 MCP 工具
所有业务调用只能通过 bundled scripts:
scripts/invoice_issuance_workflow.pyscripts/mcp_client.py
禁止直接使用 curl、requests、OpenAPI、网页浏览或手写 HTTP 请求调用企享云开票接口。服务别名和工具映射见 references/mcp-services.md。
常用原子命令:
python3 scripts/mcp_client.py --list-services
python3 scripts/mcp_client.py --check-config
python3 scripts/mcp_client.py --service blue_invoice --describe-tool issue_blue_invoice_auto
python3 scripts/mcp_client.py --tool query_invoice_issuance_quota_auto --args '{"nsrsbh":"纳税人识别号"}'
python3 scripts/mcp_client.py --tool query_invoice_tax_classification_auto --args '{"nsrsbh":"纳税人识别号","xmmc":"商品或项目名称","aggOrgId":"企业ID"}'
python3 scripts/mcp_client.py --tool issue_blue_invoice_auto --args @/tmp/invoice-data.json
支持服务:
invoice_title:购方开票抬头查询invoice_classification:根据商品或项目名称查询税收分类编码face:开票人脸认证二维码和认证结果查询enterprise_info:企业信息查询、开票额度查询invoice_inquiry:已开发票列表/明细查询blue_invoice:蓝票、农产品收购发票、报废产品收购发票开具red_invoice:红字信息表申请/查询、红字发票开具
Scan to join WeChat group