erpnext-code-validator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ERPNext Code Validator Agent

ERPNext代码验证Agent

This agent validates ERPNext/Frappe code against established patterns, common pitfalls, and version compatibility requirements.
Purpose: Catch errors BEFORE deployment, not after
本Agent可对照既定模式、常见陷阱和版本兼容性要求验证ERPNext/Frappe代码。
用途:在部署前而非部署后发现错误

When to Use This Agent

何时使用该Agent

┌─────────────────────────────────────────────────────────────────────┐
│ CODE VALIDATION TRIGGERS                                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ ► Code has been generated and needs review                          │
│   "Check this Server Script before I save it"                       │
│   └── USE THIS AGENT                                                │
│                                                                     │
│ ► Code is causing errors                                            │
│   "Why isn't this working?"                                         │
│   └── USE THIS AGENT                                                │
│                                                                     │
│ ► Pre-deployment validation                                         │
│   "Is this production-ready?"                                       │
│   └── USE THIS AGENT                                                │
│                                                                     │
│ ► Code review for best practices                                    │
│   "Can this be improved?"                                           │
│   └── USE THIS AGENT                                                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 代码验证触发场景                                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ ► 代码已生成,需要评审                                              │
│   "Check this Server Script before I save it"                       │
│   └── 使用该Agent                                                │
│                                                                     │
│ ► 代码出现错误                                                      │
│   "Why isn't this working?"                                         │
│   └── 使用该Agent                                                │
│                                                                     │
│ ► 部署前验证                                                        │
│   "Is this production-ready?"                                       │
│   └── 使用该Agent                                                │
│                                                                     │
│ ► 对照最佳实践进行代码评审                                          │
│   "Can this be improved?"                                           │
│   └── 使用该Agent                                                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Validation Workflow

验证工作流

┌─────────────────────────────────────────────────────────────────────┐
│                    CODE VALIDATOR WORKFLOW                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  STEP 1: IDENTIFY CODE TYPE                                         │
│  ══════════════════════════                                         │
│  • Client Script (JavaScript)                                       │
│  • Server Script (Python sandbox)                                   │
│  • Controller (Python full)                                         │
│  • hooks.py configuration                                           │
│  • Jinja template                                                   │
│  • Whitelisted method                                               │
│                                                                     │
│  STEP 2: RUN TYPE-SPECIFIC CHECKS                                   │
│  ═════════════════════════════════                                  │
│  • Apply checklist for identified code type                         │
│  • Check syntax patterns                                            │
│  • Verify API usage                                                 │
│                                                                     │
│  STEP 3: CHECK UNIVERSAL RULES                                      │
│  ══════════════════════════════                                     │
│  • Error handling present                                           │
│  • User feedback appropriate                                        │
│  • Security considerations                                          │
│  • Performance implications                                         │
│                                                                     │
│  STEP 4: VERIFY VERSION COMPATIBILITY                               │
│  ════════════════════════════════════                               │
│  • v14/v15/v16 specific features                                    │
│  • Deprecated patterns                                              │
│  • Version-specific behaviors                                       │
│                                                                     │
│  STEP 5: GENERATE VALIDATION REPORT                                 │
│  ══════════════════════════════════                                 │
│  • Critical errors (must fix)                                       │
│  • Warnings (should fix)                                            │
│  • Suggestions (nice to have)                                       │
│  • Corrected code (if errors found)                                 │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
→ See references/workflow.md for detailed validation steps.
┌─────────────────────────────────────────────────────────────────────┐
│                    代码验证工作流                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  步骤1:识别代码类型                                               │
│  ══════════════════════════                                         │
│  • 客户端脚本(JavaScript)                                         │
│  • 服务器脚本(Python沙箱)                                         │
│  • 控制器(完整Python)                                             │
│  • hooks.py配置                                                     │
│  • Jinja模板                                                        │
│  • 白名单方法                                                       │
│                                                                     │
│  步骤2:运行特定类型检查                                           │
│  ═════════════════════════════════                                  │
│  • 对识别出的代码类型应用检查清单                                   │
│  • 检查语法模式                                                     │
│  • 验证API使用方式                                                 │
│                                                                     │
│  步骤3:检查通用规则                                               │
│  ══════════════════════════════                                     │
│  • 是否存在错误处理                                                 │
│  • 用户反馈是否合适                                                 │
│  • 安全考量                                                         │
│  • 性能影响                                                         │
│                                                                     │
│  步骤4:验证版本兼容性                                             │
│  ════════════════════════════════════                               │
│  • v14/v15/v16专属特性                                             │
│  • 已弃用的模式                                                     │
│  • 版本特定行为                                                     │
│                                                                     │
│  步骤5:生成验证报告                                               │
│  ══════════════════════════════════                                 │
│  • 严重错误(必须修复)                                             │
│  • 警告(建议修复)                                                 │
│  • 优化建议(可选修复)                                             │
│  • 修正后的代码(若发现错误)                                       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
→ 详细验证步骤请查看 references/workflow.md

Critical Checks by Code Type

按代码类型划分的关键检查项

Server Script Checks

服务器脚本检查项

┌─────────────────────────────────────────────────────────────────────┐
│ ⚠️  SERVER SCRIPT CRITICAL CHECKS                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [FATAL] Import statements                                           │
│ ═══════════════════════════                                         │
│ ❌ import json                    → Use frappe.parse_json()         │
│ ❌ from frappe.utils import X     → Use frappe.utils.X()            │
│ ❌ import requests                → IMPOSSIBLE in Server Script     │
│                                                                     │
│ [FATAL] Undefined variables                                         │
│ ════════════════════════════                                        │
│ ❌ self.field                     → Use doc.field                   │
│ ❌ document.field                 → Use doc.field                   │
│                                                                     │
│ [FATAL] Wrong event handling                                        │
│ ═══════════════════════════════                                     │
│ ❌ try/except for validation      → Just frappe.throw()             │
│                                                                     │
│ [ERROR] Event name mismatch                                         │
│ ═══════════════════════════                                         │
│ ❌ Event "Before Save" code in "After Save" script                  │
│                                                                     │
│ [WARNING] Missing validation                                        │
│ ═══════════════════════════════                                     │
│ ⚠️  No null/empty checks before operations                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ ⚠️  服务器脚本关键检查项                                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [致命错误] 导入语句                                                 │
│ ═══════════════════════════                                         │
│ ❌ import json                    → Use frappe.parse_json()         │
│ ❌ from frappe.utils import X     → Use frappe.utils.X()            │
│ ❌ import requests                → IMPOSSIBLE in Server Script     │
│                                                                     │
│ [致命错误] 未定义变量                                               │
│ ════════════════════════════                                        │
│ ❌ self.field                     → Use doc.field                   │
│ ❌ document.field                 → Use doc.field                   │
│                                                                     │
│ [致命错误] 错误的事件处理                                           │
│ ═══════════════════════════════                                     │
│ ❌ try/except for validation      → Just frappe.throw()             │
│                                                                     │
│ [错误] 事件名称不匹配                                               │
│ ═══════════════════════════                                         │
│ ❌ Event "Before Save" code in "After Save" script                  │
│                                                                     │
│ [警告] 缺少验证                                                     │
│ ═══════════════════════════════                                     │
│ ⚠️  No null/empty checks before operations                          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Client Script Checks

客户端脚本检查项

┌─────────────────────────────────────────────────────────────────────┐
│ CLIENT SCRIPT CRITICAL CHECKS                                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [FATAL] Wrong API usage                                             │
│ ═════════════════════════                                           │
│ ❌ frappe.db.get_value()          → Server-side only!               │
│ ❌ frappe.get_doc()               → Server-side only!               │
│ ✓  frappe.call() for server data                                    │
│                                                                     │
│ [FATAL] Missing async handling                                      │
│ ══════════════════════════════                                      │
│ ❌ let result = frappe.call()     → Returns undefined               │
│ ✓  frappe.call({callback: fn})   → Use callback                     │
│ ✓  await frappe.call({async:false}) → Or async/await               │
│                                                                     │
│ [ERROR] Field refresh issues                                        │
│ ════════════════════════════                                        │
│ ❌ frm.set_value() without refresh                                  │
│ ✓  frm.set_value() then frm.refresh_field()                        │
│                                                                     │
│ [WARNING] Form state checks                                         │
│ ═══════════════════════════                                         │
│ ⚠️  Not checking frm.doc.__islocal for new docs                     │
│ ⚠️  Not checking frm.doc.docstatus for submitted docs               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 客户端脚本关键检查项                                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [致命错误] 错误的API使用方式                                       │
│ ═════════════════════════                                           │
│ ❌ frappe.db.get_value()          → Server-side only!               │
│ ❌ frappe.get_doc()               → Server-side only!               │
│ ✓  frappe.call() for server data                                    │
│                                                                     │
│ [致命错误] 缺少异步处理                                             │
│ ══════════════════════════════                                      │
│ ❌ let result = frappe.call()     → Returns undefined               │
│ ✓  frappe.call({callback: fn})   → Use callback                     │
│ ✓  await frappe.call({async:false}) → Or async/await               │
│                                                                     │
│ [错误] 字段刷新问题                                                 │
│ ════════════════════════════                                        │
│ ❌ frm.set_value() without refresh                                  │
│ ✓  frm.set_value() then frm.refresh_field()                        │
│                                                                     │
│ [警告] 表单状态检查                                                 │
│ ═══════════════════════════                                         │
│ ⚠️  Not checking frm.doc.__islocal for new docs                     │
│ ⚠️  Not checking frm.doc.docstatus for submitted docs               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Controller Checks

控制器检查项

┌─────────────────────────────────────────────────────────────────────┐
│ CONTROLLER CRITICAL CHECKS                                          │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [FATAL] Wrong lifecycle usage                                       │
│ ═════════════════════════════                                       │
│ ❌ Modifying self.field in on_update → Changes NOT saved!           │
│ ✓  Use frappe.db.set_value() in on_update                          │
│                                                                     │
│ [FATAL] Missing super() call                                        │
│ ════════════════════════════                                        │
│ ❌ def validate(self): pass        → Breaks parent validation       │
│ ✓  def validate(self): super().validate()                          │
│                                                                     │
│ [ERROR] Transaction assumptions                                     │
│ ═══════════════════════════════                                     │
│ ❌ Assuming rollback on error in on_update                          │
│    (only validate and before_* roll back on error)                 │
│                                                                     │
│ [ERROR] Circular save                                               │
│ ══════════════════════                                              │
│ ❌ self.save() inside lifecycle hooks                               │
│ ❌ doc.save() for same document in hooks                            │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
→ See references/checklists.md for complete checklists.
┌─────────────────────────────────────────────────────────────────────┐
│ 控制器关键检查项                                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│ [致命错误] 错误的生命周期使用方式                                   │
│ ═════════════════════════════                                       │
│ ❌ Modifying self.field in on_update → Changes NOT saved!           │
│ ✓  Use frappe.db.set_value() in on_update                          │
│                                                                     │
│ [致命错误] 缺少super()调用                                         │
│ ════════════════════════════                                        │
│ ❌ def validate(self): pass        → Breaks parent validation       │
│ ✓  def validate(self): super().validate()                          │
│                                                                     │
│ [错误] 事务假设                                                     │
│ ═══════════════════════════════                                     │
│ ❌ Assuming rollback on error in on_update                          │
│    (only validate and before_* roll back on error)                 │
│                                                                     │
│ [错误] 循环保存                                                     │
│ ══════════════════════                                              │
│ ❌ self.save() inside lifecycle hooks                               │
│ ❌ doc.save() for same document in hooks                            │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
→ 完整检查清单请查看 references/checklists.md

Validation Report Format

验证报告格式

markdown
undefined
markdown
undefined

Code Validation Report

代码验证报告

Code Type: [Server Script / Client Script / Controller / etc.]

代码类型:[服务器脚本/客户端脚本/控制器等]

Target DocType: [DocType name]

目标DocType:[DocType名称]

Event/Trigger: [Event name]

事件/触发条件:[事件名称]



🔴 CRITICAL ERRORS (Must Fix)

🔴 严重错误(必须修复)

LineIssueFix
3Import statement in Server ScriptUse frappe.utils.X() directly
行号问题修复方案
3服务器脚本中使用导入语句直接使用frappe.utils.X()

🟡 WARNINGS (Should Fix)

🟡 警告(建议修复)

LineIssueRecommendation
12No null check before .lower()Add: if value: value.lower()
行号问题建议方案
12调用.lower()前未做空值检查添加:if value: value.lower()

🔵 SUGGESTIONS (Nice to Have)

🔵 优化建议(可选修复)

LineSuggestion
8Consider using frappe.db.get_value for single field

行号建议
8考虑使用frappe.db.get_value获取单个字段

Corrected Code

修正后的代码

python
undefined
python
undefined

[Corrected version with all critical errors fixed]

[修复所有严重错误后的代码版本]

undefined
undefined

Version Compatibility

版本兼容性

VersionStatus
v14✅ Compatible
v15✅ Compatible
v16✅ Compatible
undefined
版本状态
v14✅ 兼容
v15✅ 兼容
v16✅ 兼容
undefined

Universal Validation Rules

通用验证规则

These apply to ALL code types:
以下规则适用于所有代码类型:

Security Checks

安全检查项

CheckSeverityDescription
SQL InjectionCRITICALRaw user input in SQL queries
Permission bypassCRITICALMissing permission checks before operations
XSS vulnerabilityHIGHUnescaped user input in HTML
Sensitive data exposureHIGHLogging passwords/tokens
检查内容严重程度描述
SQL注入严重SQL查询中使用原始用户输入
权限绕过严重操作前缺少权限检查
XSS漏洞HTML中使用未转义的用户输入
敏感数据泄露记录密码/令牌等敏感数据

Error Handling Checks

错误处理检查项

CheckSeverityDescription
Silent failuresHIGHCatching exceptions without handling
Missing user feedbackMEDIUMErrors not communicated to user
Generic error messagesLOW"An error occurred" without details
检查内容严重程度描述
静默失败捕获异常但未处理
缺少用户反馈错误未告知用户
通用错误信息仅显示“发生错误”无详细信息

Performance Checks

性能检查项

CheckSeverityDescription
Query in loopHIGHfrappe.db.* inside for loop
Unbounded queryMEDIUMSELECT without LIMIT
Unnecessary get_docLOWget_doc when get_value suffices
→ See references/examples.md for validation examples.
检查内容严重程度描述
循环中执行查询for循环内使用frappe.db.*
无限制查询SELECT语句未加LIMIT
不必要的get_doc调用可用get_value时使用get_doc
→ 验证示例请查看 references/examples.md

Version-Specific Validations

特定版本验证项

v16 Features (Fail on v14/v15)

v16特性(在v14/v15中无法运行)

python
undefined
python
undefined

These ONLY work on v16+

这些仅在v16+中可用

extend_doctype_class = {} # hooks.py - v16 only naming_rule = "UUID" # DocType - v16 only pdf_renderer = "chrome" # Print Format - v16 only
undefined
extend_doctype_class = {} # hooks.py - v16 only naming_rule = "UUID" # DocType - v16 only pdf_renderer = "chrome" # Print Format - v16 only
undefined

Deprecated Patterns (Warn)

已弃用的模式(警告)

python
undefined
python
undefined

DEPRECATED - still works but should update

已弃用 - 仍可运行但建议更新

frappe.bean() # Use frappe.get_doc() frappe.msgprint(raise_exception=True) # Use frappe.throw() job_name parameter # Use job_id (v15+)
undefined
frappe.bean() # Use frappe.get_doc() frappe.msgprint(raise_exception=True) # Use frappe.throw() job_name parameter # Use job_id (v15+)
undefined

Version-Specific Behaviors

版本特定行为

Behaviorv14v15/v16
Scheduler tick240s60s
Background job dedupjob_namejob_id
行为v14v15/v16
调度器间隔240秒60秒
后台任务去重job_namejob_id

Quick Validation Commands

快速验证指令

Server Script Quick Check

服务器脚本快速检查

  1. ❌ Any
    import
    statements? → FATAL
  2. ❌ Any
    self.
    references? → FATAL (use
    doc.
    )
  3. ❌ Any
    try/except
    ? → WARNING (usually wrong)
  4. ✅ Uses
    frappe.throw()
    for validation errors? → GOOD
  5. ✅ Uses
    doc.field
    for document access? → GOOD
  1. ❌ 是否存在
    import
    语句?→ 致命错误
  2. ❌ 是否存在
    self.
    引用?→ 致命错误(使用
    doc.
  3. ❌ 是否存在
    try/except
    ?→ 警告(通常使用方式错误)
  4. ✅ 是否使用
    frappe.throw()
    处理验证错误?→ 正确
  5. ✅ 是否使用
    doc.field
    访问文档字段?→ 正确

Client Script Quick Check

客户端脚本快速检查

  1. ❌ Any
    frappe.db.*
    calls? → FATAL (server-side only)
  2. ❌ Any
    frappe.get_doc()
    calls? → FATAL (server-side only)
  3. frappe.call()
    without callback? → FATAL (async issue)
  4. ✅ Uses
    frm.doc.field
    for field access? → GOOD
  5. ✅ Uses
    frm.refresh_field()
    after changes? → GOOD
  1. ❌ 是否存在
    frappe.db.*
    调用?→ 致命错误(仅服务器端可用)
  2. ❌ 是否存在
    frappe.get_doc()
    调用?→ 致命错误(仅服务器端可用)
  3. frappe.call()
    未使用回调?→ 致命错误(异步问题)
  4. ✅ 是否使用
    frm.doc.field
    访问字段?→ 正确
  5. ✅ 修改后是否使用
    frm.refresh_field()
    ?→ 正确

Controller Quick Check

控制器快速检查

  1. ❌ Modifying
    self.*
    in
    on_update
    ? → ERROR (won't save)
  2. ❌ Missing
    super().method()
    calls? → WARNING
  3. self.save()
    in lifecycle hook? → FATAL (circular)
  4. ✅ Imports at top of file? → GOOD (controllers allow imports)
  5. ✅ Error handling with try/except? → GOOD (controllers allow this)
  1. ❌ 在
    on_update
    中修改
    self.*
    ?→ 错误(不会保存)
  2. ❌ 缺少
    super().method()
    调用?→ 警告
  3. ❌ 生命周期钩子中调用
    self.save()
    ?→ 致命错误(循环调用)
  4. ✅ 导入语句是否在文件顶部?→ 正确(控制器允许导入)
  5. ✅ 是否使用try/except处理错误?→ 正确(控制器允许使用)

Integration with Other Skills

与其他技能的集成

This validator uses knowledge from:
SkillWhat It Provides
erpnext-syntax-*
Correct syntax patterns
erpnext-impl-*
Correct implementation patterns
erpnext-errors-*
Error handling patterns
erpnext-database
Query patterns and pitfalls
erpnext-permissions
Permission check patterns
erpnext-api-patterns
API response patterns
本验证器使用以下技能的相关知识:
技能提供内容
erpnext-syntax-*
正确的语法模式
erpnext-impl-*
正确的实现模式
erpnext-errors-*
错误处理模式
erpnext-database
查询模式与常见陷阱
erpnext-permissions
权限检查模式
erpnext-api-patterns
API响应模式

Validation Depth Levels

验证深度级别

LevelChecksUse When
QuickFatal errors onlyInitial scan
Standard+ WarningsPre-deployment
Deep+ Suggestions + OptimizationProduction review
Default: Standard level for most validations.
级别检查内容使用场景
快速仅检查致命错误初始扫描
标准+ 警告项部署前检查
深度+ 优化建议 + 性能优化生产环境评审
默认:大多数验证使用标准级别。