mcpField
S
support-ticket

support-ticket

github.com/frappe开发1598 次安装2 天前更新
代码仓库

关于 support-ticket

此技能为技术和非技术支持工单规定了迭代调查流程,从分类、索取数据到诊断,并在适当时修复。它强调客户仅使用 Desk、按版本分析代码,以及范围明确的回复和修复。

主要功能

  1. 01工单分类与迭代诊断
  2. 02通过 Desk System Console 索取数据
  3. 03按固定版本调查代码
  4. 04修复前检查定制项
  5. 05带防护且可验证的数据修复

适用场景

  1. 01分类支持工单并索取证据
  2. 02区分代码缺陷与数据异常
  3. 03根据调查结果起草简短客户回复
  4. 04准备安全的定向数据修复

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/frappe/skills --skill support-ticket

安装后在 Claude Code 中输入/support-ticket确认已加载。

详细介绍

支持工单工作流

适用于技术和非技术用户。任何人都可以执行步骤 1–3,对问题进行分类、索取数据并起草客户回复。步骤 4–5(排除自定义项并修复)需要开发人员,但非技术用户可以在找到明确答案或起草好回复后停止。

输入:工单编号(拉取问题和邮件往来),或粘贴的问题描述。同时拉取附件,例如图片和 xlsx/csv 文件;忽略视频。

开始调查前,请在醒目位置(会话/任务标题)注明工单编号,以便轻松找到相关对话。

**迭代循环,而非一次性处理:**分类 → 索取数据 → 分析 → 深入调查 → 排除自定义项 → 重复,直到确定根本原因。预计需要多轮数据往返。只有完成这些步骤后,才进行修复(步骤 5)。

会话规则:

  • **客户只能访问 Desk。**不能使用 SSH、不能运行 bench 命令、不能查看服务器日志或文件系统。绝不要索取无法通过 System Console 或 Desk UI 获取的信息。
  • **保持简洁——每个步骤用一两行解读输出,并给出下一个代码片段。**不要写总结,不要重述问题。
  • 尽早确定应用版本;分析时以该版本的代码库为准——不同分支可能存在差异。检出或读取与客户已安装版本匹配的分支/标签:git -C apps/<app> show <branch>:path/to/file.py,或 git -C apps/<app> grep <term> <branch> -- '*.py'。
  • 客户回复草稿:尽可能简短,使用非常简单的语言,并以调查结果为依据。只输出回复正文,不要输出其他内容——不要加“以下是草稿”之类的开场白,不要附带说明,也不要在末尾提出后续问题——以便直接复制发送。
  • **自定义项属于灰色地带——不要认可、实施或协助处理。**框架自定义项(Client Scripts、Custom Fields、Server Scripts、Property Setters)可以帮助终端用户弥补实际存在的缺口,但不属于核心支持范围。不要代表客户提出、编写或实施自定义项。如果只有通过自定义项才能满足请求,请明确说明并就此停止——不要提供脚本或操作指南。

阅读工单(Frappe Helpdesk)

如果工单存放在 Frappe Helpdesk(HD Ticket)中,请使用只读 Frappe API 客户端(例如 frappectl)或直接使用 REST API,拉取工单及其邮件往来:

  • 工单字段:frappectl doc get "HD Ticket" <name>
  • 邮件往来 + 内部备注:frappectl doc list Communication 会返回 [](受权限过滤),所以不要使用它。请改用:
    frappectl api "method/frappe.desk.form.load.get_docinfo?doctype=HD%20Ticket&name=<name>"
    
    docinfo.communications = 邮件往来(content、sender、 communication_date);docinfo.comments = Agent 内部备注。

**刷新对话:**收到检查最新回复或刷新上下文的请求时,请重新运行 get_docinfo 调用,并读取 docinfo.communications 中的最新条目(按 communication_date 排序)——服务器上的邮件往来会持续更新,因此应重新获取,而不要依赖之前拉取的内容。

1. 分类 → 确定处理结果

根据代码和数据形成自己的假设——工单以及任何客户端/Agent 对话串都只是症状,而非诊断;不要锚定于猜测的原因。数据证实之前不要修复。处理结果——后面的结果通常只有完成步骤 2–4 后才能确定:

  • 功能行为/“工作原理”(设置、权限、对工作流的误解) → 根据调查结果进行说明;拟好给客户端的回复。不做修复。
  • 已确认的代码 Bug,可通过补丁修复 → 按步骤 2–5 修复。
  • 数据不一致(代码正确;客户端的数据处于错误状态——孤立/过时的行、未解除关联的分类账分录、未结项目异常)→ 对照客户端的实际数据检查代码,证明问题出在记录而非逻辑;然后进行有针对性的数据修复,而非代码补丁。参见步骤 5。
  • Bug,但根因分析(RCA)表明需要重大重构/破坏性更改 → 告知用户。不要修复。
  • 功能请求 → 告知用户这是功能请求。不要修复。
  • 已修复/版本过旧 → 提醒客户端更新应用。不要修复。尽早确定其提交版本 → 标签,并与最新版本对比。许多修复已在后续版本中上线。如果修复存在于较新的标签中,或者症状是同步缺失、更新并迁移即可解决,请让他们更新所需应用并重新检查,再进一步调查。

2. 索取数据——提供可运行代码,不要提供文字说明

提供一段代码,让客户端粘贴到站点内的 System Console (Desk → /app/system-console)——这是一个 RestrictedPython 沙盒,不是 bench console/SSH。遵循以下沙盒规则。为每条打印结果添加标签 (print("outstanding:", ...)),以便返回的输出能明确对应到具体问题;将相关问题合并到一段代码中,尽量减少往返次数。

3. 分析 → 得出结论或循环

  • 结论明确 → 给出答案,完成。
  • 指向代码 → 在固定版本中追踪相关代码路径;排查边界情况/Bug。
  • 不明确 → 调整假设,返回步骤 2。

4. 排除自定义项(当代码表明其应正常工作时)

如果根据固定版本进行推理后认为行为正确,但客户端仍遇到问题,且你无法在本地复现,那么在认定这是核心 Bug 或无解之前,应先怀疑站点级自定义项。此操作必须在步骤 5 之前完成——绝不要针对由自定义项负责的行为提交核心修复。 如果存在自定义应用,请检查“Audit System Hooks”报告,以及相关对象(doctype / 报告 / 白名单方法)的客户端/服务器脚本、自定义字段和属性设置器。

5. 修复

代码 Bug
  • 在修复前深入分析边界情况和回归影响;不要只修补症状。必要时添加回归测试——确保没有修复时测试会失败。
  • 在专用测试站点(例如 <app>-test.localhost)上复现并验证,绝不要在客户端的站点上操作。
  • 按照 code-style 和 frappe-app-dev 技能编写修复。
分支与回移
  • 编辑前先创建分支——绝不要直接在主开发分支(develop)或发布分支上编辑。
  • 先在 develop 上修复,再回移到所有仍受维护的发布分支;不要回移到最老的受维护版本以下。
  • 提交前等待评审;只有在收到请求时才创建 PR。
数据修复(数据不一致处理结果)

通过客户端的 System Console 执行(只有勾选 Commit 框后,写入才会持久保存)。脚本必须:

  • 安全——每次写入都必须以能证明该行有误的条件作为防护(例如,源文档 docstatus == 2 且该行仍处于有效状态),确保对正确数据不做任何操作。
  • 幂等——修复后再次运行不会产生任何变化。
  • 精简——只触及已确认的错误行,绝不盲目批量更新。
  • 可验证——打印修改前后的数据,让客户端的输出能够确认更改。 先请会计人员/用户确认正确的最终状态。如果同一错误状态可能再次出现,则应另外修复导致问题的根因代码缺陷。

System Console 沙盒规则

通过 safe_exec 运行——与 Server Scripts 使用相同的沙盒。

只有打印的输出可见(print());单独的表达式不会输出内容。优先使用 Python 模式,但读取复杂数据时使用 SQL 模式。查询必须设置 limit。

不允许:

  • 序列解包——a, b = x、for a, b in items:、在推导式中使用 k, v。RestrictedPython 会生成一个 _unpack_sequence_ 守卫,但命名空间中没有它 → NameError: name '_unpack_sequence_' is not defined。改用索引(r["a"]、r[0]);将字典值保留为字典,不要转换为元组。
  • import(任何形式)——编译时会被拦截;即使间接导入也会失败,并报错 ImportError: __import__ not found。你无法导入应用代码(from erpnext... import x),也不能通过 frappe.get_attr / frappe.call 访问(不在命名空间中)。若要测试某个辅助函数的逻辑,使用允许的调用在代码中复现;不要尝试调用真实函数。
  • frappe.get_installed_apps——不在命名空间中(AttributeError)。通过 SQL 获取应用:SELECT app_name FROM \tabInstalled Application`(SQL 模式),或检查某个应用:frappe.db.exists("Module Def", {"app_name": "erpnext"})`。
  • frappe.get_single_value——不在命名空间中;改用 frappe.db.get_single_value("Doctype", "field")。
  • frappe.get_conf / conf / get_site_config / local / cache / get_single——不在命名空间中。
  • frappe.parse_json——改用 frappe.utils.parse_json 或 json.loads。
  • .format()/.format_map()——改用 f-string。
  • 以下划线 _ 开头的属性(doc.__dict__、obj._x)。
  • 非白名单的 frappe.utils.X(例如 get_site_path、get_files_path)。
  • open()/文件 I/O;非 SELECT 类型的 frappe.db.sql。

允许:

  • ORM:frappe.get_doc(真实的 Document)、get_all、get_list、 get_cached_doc、get_last_doc、get_meta、new_doc、copy_doc、 get_mapped_doc。
  • frappe.db:get_value、set_value、get_single_value、get_list、 get_all、exists、count、get_default、escape、sql(SELECT/EXPLAIN)、 commit/rollback(只有勾选 Commit 复选框后,写入才会持久化)。
  • frappe.utils:getdate、get_datetime、nowdate、today、now、 now_datetime、add_days、add_months、date_diff、get_first_day、 get_last_day、flt、cint、cstr、fmt_money、money_in_words、 parse_json、get_link_to_form。
  • 其他:print、frappe.log、frappe.msgprint、frappe.throw、frappe.qb、 frappe.get_system_settings、frappe.session、frappe.form_dict、 json.loads/dumps、_dict、内置函数(dict/list/set/tuple、 len/str/int/float/round/bool、range/enumerate/sorted/sum/min/max)、 推导式、f-string、循环。

评论

支持 Markdown