erpnext-impl-customapp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ERPNext Custom App - Implementation

ERPNext自定义应用 - 实施指南

This skill helps you determine HOW to build and structure Frappe/ERPNext custom apps. For exact syntax, see
erpnext-syntax-customapp
.
Version: v14/v15/v16 compatible (differences noted)

本技能将帮助你确定如何构建和规划Frappe/ERPNext自定义应用的结构。如需具体语法参考,请查看
erpnext-syntax-customapp
版本:兼容v14/v15/v16版本(版本差异已标注)

Main Decision: What Are You Building?

核心决策:你要构建什么?

┌─────────────────────────────────────────────────────────────────────────┐
│ WHAT DO YOU WANT TO CREATE?                                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ ► Completely new Frappe/ERPNext app?                                    │
│   └─► See: NEW APP WORKFLOW                                             │
│                                                                         │
│ ► Extend existing ERPNext functionality?                                │
│   └─► See: EXTENSION DECISION                                           │
│                                                                         │
│ ► Migrate data between fields/DocTypes?                                 │
│   └─► See: PATCH vs FIXTURE DECISION                                    │
│                                                                         │
│ ► Export configuration for deployment?                                  │
│   └─► See: FIXTURE WORKFLOW                                             │
│                                                                         │
│ ► Update existing app to newer Frappe version?                          │
│   └─► See: VERSION UPGRADE WORKFLOW                                     │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│ 你想要创建什么?                                                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ ► 全新的Frappe/ERPNext应用?                                             │
│   └─► 参考:新应用工作流                                               │
│                                                                         │
│ ► 扩展现有ERPNext功能?                                                 │
│   └─► 参考:扩展方案决策                                               │
│                                                                         │
│ ► 在不同字段/DocType之间迁移数据?                                       │
│   └─► 参考:补丁与Fixture决策                                           │
│                                                                         │
│ ► 导出配置用于部署?                                                     │
│   └─► 参考:Fixture工作流                                               │
│                                                                         │
│ ► 将现有应用升级到更高版本的Frappe?                                     │
│   └─► 参考:版本升级工作流                                             │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Decision 1: Do You Need a Custom App?

决策1:你是否需要自定义应用?

┌─────────────────────────────────────────────────────────────────────────┐
│ DO YOU ACTUALLY NEED A CUSTOM APP?                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ What changes do you need?                                               │
│                                                                         │
│ ► Add fields to existing DocType?                                       │
│   └─► NO APP NEEDED: Use Custom Field + Property Setter                 │
│       (Can be exported as fixtures from ANY app)                        │
│                                                                         │
│ ► Simple automation/validation?                                         │
│   └─► NO APP NEEDED: Server Script or Client Script                     │
│       (Stored in database, no deployment needed)                        │
│                                                                         │
│ ► Complex business logic, new DocTypes, or Python code?                 │
│   └─► YES, CREATE APP: You need controllers, models, and deployment     │
│                                                                         │
│ ► Integration with external system?                                     │
│   └─► USUALLY YES: APIs need whitelisted methods, scheduled sync        │
│                                                                         │
│ ► Custom reports with complex queries?                                  │
│   └─► DEPENDS: Script Report (no app) vs Query Report (app optional)    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
Rule: Start with the SIMPLEST solution. Server Scripts + Custom Fields solve 70% of customization needs without a custom app.

┌─────────────────────────────────────────────────────────────────────────┐
│ 你真的需要自定义应用吗?                                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ 你需要进行哪些更改?                                                     │
│                                                                         │
│ ► 为现有DocType添加字段?                                               │
│   └─► 无需应用:使用Custom Field + Property Setter                       │
│       (可从任意应用导出为fixtures)                                      │
│                                                                         │
│ ► 简单的自动化/验证?                                                   │
│   └─► 无需应用:使用Server Script或Client Script                         │
│       (存储在数据库中,无需部署)                                        │
│                                                                         │
│ ► 复杂业务逻辑、新DocType或Python代码?                                 │
│   └─► 需要创建应用:你需要控制器、模型和部署流程                         │
│                                                                         │
│ ► 与外部系统集成?                                                     │
│   └─► 通常需要:API需要白名单方法、定时同步                             │
│                                                                         │
│ ► 包含复杂查询的自定义报表?                                           │
│   └─► 视情况而定:Script Report(无需应用) vs Query Report(可选应用)  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
原则:从最简单的解决方案入手。Server Script和Custom Fields无需自定义应用即可解决70%的定制需求。

Decision 2: Extension Strategy

决策2:扩展策略

┌─────────────────────────────────────────────────────────────────────────┐
│ HOW TO EXTEND ERPNext?                                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ ► Add fields to existing DocType (e.g., Sales Invoice)?                 │
│   └─► Custom Field (via UI or fixtures)                                 │
│   └─► Property Setter for behavior changes                              │
│                                                                         │
│ ► Modify DocType behavior/logic?                                        │
│   ├─► v16: Use `extend_doctype_class` hook (PREFERRED)                  │
│   └─► v14/v15: Use `doc_events` hooks in hooks.py                       │
│                                                                         │
│ ► Override Jinja template?                                              │
│   └─► Copy template to your app's templates/ folder                     │
│   └─► Register via `jinja.override_template` in hooks.py                │
│                                                                         │
│ ► Add new DocType related to existing?                                  │
│   └─► Create in your app's module                                       │
│   └─► Link via Link field or Dynamic Link                               │
│                                                                         │
│ ► Add new workspace/menu items?                                         │
│   └─► Create Workspace DocType in your app                              │
│   └─► Or use `standard_portal_menu_items` hook                          │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
See:
references/decision-tree.md
for detailed extension patterns.

┌─────────────────────────────────────────────────────────────────────────┐
│ 如何扩展ERPNext?                                                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ ► 为现有DocType添加字段(如销售发票)?                                 │
│   └─► Custom Field(通过UI或fixtures)                                   │
│   └─► 使用Property Setter修改行为                                      │
│                                                                         │
│ ► 修改DocType的行为/逻辑?                                             │
│   ├─► v16:使用`extend_doctype_class`钩子(推荐)                        │
│   └─► v14/v15:在hooks.py中使用`doc_events`钩子                         │
│                                                                         │
│ ► 覆盖Jinja模板?                                                       │
│   └─► 将模板复制到你的应用templates/目录中                             │
│   └─► 在hooks.py中通过`jinja.override_template`注册                      │
│                                                                         │
│ ► 创建与现有功能关联的新DocType?                                       │
│   └─► 在你的应用模块中创建                                             │
│   └─► 通过Link字段或Dynamic Link关联                                   │
│                                                                         │
│ ► 添加新的工作区/菜单项?                                               │
│   └─► 在你的应用中创建Workspace DocType                                │
│   └─► 或使用`standard_portal_menu_items`钩子                            │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
参考
references/decision-tree.md
包含详细的扩展模式。

Decision 3: Patch vs Fixture

决策3:补丁 vs Fixture

┌─────────────────────────────────────────────────────────────────────────┐
│ SHOULD THIS BE A PATCH OR A FIXTURE?                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ Is it CONFIGURATION that should be the same everywhere?                 │
│ (Custom Fields, Roles, Workflows, Property Setters)                     │
│   └─► USE FIXTURE                                                       │
│                                                                         │
│ Is it a ONE-TIME data transformation?                                   │
│ (Migrate old field values, cleanup bad data, populate defaults)         │
│   └─► USE PATCH                                                         │
│                                                                         │
│ Does it need to run BEFORE schema changes?                              │
│ (Backup data from field that will be deleted)                           │
│   └─► USE PATCH with [pre_model_sync]                                   │
│                                                                         │
│ Does it need to run AFTER schema changes?                               │
│ (Populate newly added field with calculated values)                     │
│   └─► USE PATCH with [post_model_sync]                                  │
│                                                                         │
│ Is it master data / lookup tables?                                      │
│ (Categories, Status options, Configuration records)                     │
│   └─► USE FIXTURE for initial, PATCH for updates                        │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
See:
references/decision-tree.md
for patch timing flowchart.

┌─────────────────────────────────────────────────────────────────────────┐
│ 应该使用补丁还是Fixture?                                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ 是否是需要在所有环境中保持一致的配置?                                   │
│ (Custom Fields、角色、工作流、Property Setters)                         │
│   └─► 使用Fixture                                                       │
│                                                                         │
│ 是否是一次性的数据转换?                                               │
│ (迁移旧字段值、清理无效数据、填充默认值)                               │
│   └─► 使用补丁                                                         │
│                                                                         │
│ 是否需要在架构变更前运行?                                             │
│ (备份即将被删除的字段中的数据)                                         │
│   └─► 使用带有[pre_model_sync]的补丁                                    │
│                                                                         │
│ 是否需要在架构变更后运行?                                             │
│ (用计算值填充新增字段)                                                 │
│   └─► 使用带有[post_model_sync]的补丁                                   │
│                                                                         │
│ 是否是主数据/查找表?                                                   │
│ (分类、状态选项、配置记录)                                             │
│   └─► 初始设置使用Fixture,更新时使用补丁                               │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
参考
references/decision-tree.md
包含补丁时机流程图。

Decision 4: Module Organization

决策4:模块组织

┌─────────────────────────────────────────────────────────────────────────┐
│ HOW MANY MODULES DO YOU NEED?                                           │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ Small app (1-5 DocTypes, single purpose)?                               │
│   └─► ONE MODULE with app name                                          │
│       Example: my_app/my_app/ (module "My App")                         │
│                                                                         │
│ Medium app (6-15 DocTypes, multiple areas)?                             │
│   └─► 2-4 MODULES by functional area                                    │
│       Example: core/, settings/, integrations/                          │
│                                                                         │
│ Large app (15+ DocTypes, complex domain)?                               │
│   └─► MODULES by business domain                                        │
│       Example: inventory/, sales/, purchasing/, settings/               │
│                                                                         │
│ Multi-tenant or vertical solution?                                      │
│   └─► Consider MULTIPLE APPS instead                                    │
│       Base app + vertical-specific apps                                 │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
Rule: Each DocType belongs to EXACTLY one module. Choose module = where would a user look for this DocType?

┌─────────────────────────────────────────────────────────────────────────┐
│ 你需要多少个模块?                                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ 小型应用(1-5个DocType,单一用途)?                                   │
│   └─► 一个与应用同名的模块                                             │
│       示例:my_app/my_app/(模块名为"My App")                           │
│                                                                         │
│ 中型应用(6-15个DocType,多个业务领域)?                               │
│   └─► 按功能领域划分2-4个模块                                          │
│       示例:core/、settings/、integrations/                              │
│                                                                         │
│ 大型应用(15个以上DocType,复杂业务领域)?                             │
│   └─► 按业务领域划分模块                                                │
│       示例:inventory/、sales/、purchasing/、settings/                   │
│                                                                         │
│ 多租户或垂直行业解决方案?                                             │
│   └─► 考虑使用多个应用                                                  │
│       基础应用 + 垂直行业专属应用                                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
原则:每个DocType必须属于且仅属于一个模块。选择模块的标准是:用户会在哪里查找这个DocType?

Quick Implementation Workflows

快速实施工作流

New App Workflow

新应用工作流

1. Create app structure    → bench new-app my_app
2. Configure pyproject     → Edit pyproject.toml (v15+) or setup.py (v14)
3. Define modules          → Edit modules.txt
4. Create DocTypes         → bench --site mysite new-doctype MyDocType
5. Write controllers       → my_app/doctype/my_doctype/my_doctype.py
6. Configure hooks         → hooks.py for integration
7. Export fixtures         → bench --site mysite export-fixtures
8. Test installation       → bench --site testsite install-app my_app
See:
references/workflows.md
for detailed steps.
1. 创建应用结构    → bench new-app my_app
2. 配置pyproject     → 编辑pyproject.toml(v15+)或setup.py(v14)
3. 定义模块          → 编辑modules.txt
4. 创建DocTypes         → bench --site mysite new-doctype MyDocType
5. 编写控制器       → my_app/doctype/my_doctype/my_doctype.py
6. 配置钩子         → hooks.py用于集成
7. 导出fixtures         → bench --site mysite export-fixtures
8. 测试安装       → bench --site testsite install-app my_app
参考
references/workflows.md
包含详细步骤。

Patch Workflow

补丁工作流

1. Plan the migration      → What data moves where?
2. Choose timing           → [pre_model_sync] or [post_model_sync]
3. Write patch file        → myapp/patches/v1_0/description.py
4. Add to patches.txt      → Under correct section
5. Test locally            → bench --site testsite migrate
6. Handle errors           → Add rollback logic if needed
7. Test on copy of prod    → ALWAYS before production
See:
references/workflows.md
for patch patterns.
1. 规划迁移      → 数据需要从哪里迁移到哪里?
2. 选择执行时机           → [pre_model_sync] 或 [post_model_sync]
3. 编写补丁文件        → myapp/patches/v1_0/description.py
4. 添加到patches.txt      → 在正确的章节下添加
5. 本地测试            → bench --site testsite migrate
6. 处理错误           → 如有需要添加回滚逻辑
7. 在生产环境副本上测试    → 务必在生产环境前测试
参考
references/workflows.md
包含补丁模式。

Fixture Workflow

Fixture工作流

1. Configure hooks.py      → Define fixtures list with filters
2. Make changes via UI     → Custom Fields, Property Setters, etc.
3. Export fixtures         → bench --site mysite export-fixtures --app my_app
4. Verify JSON files       → Check my_app/fixtures/*.json
5. Commit to version control
6. Test import             → bench --site newsite migrate
See:
references/workflows.md
for fixture strategies.

1. 配置hooks.py      → 定义带有过滤器的fixtures列表
2. 通过UI进行更改     → Custom Fields、Property Setters等
3. 导出fixtures         → bench --site mysite export-fixtures --app my_app
4. 验证JSON文件       → 检查my_app/fixtures/*.json
5. 提交到版本控制
6. 测试导入             → bench --site newsite migrate
参考
references/workflows.md
包含Fixture策略。

Version-Specific Considerations

版本特定注意事项

Aspectv14v15v16
Build configsetup.pypyproject.tomlpyproject.toml
DocType extensiondoc_eventsdoc_events
extend_doctype_class
preferred
Python minimum3.103.103.11
INI patches
Fixtures formatJSONJSONJSON
方面v14v15v16
构建配置setup.pypyproject.tomlpyproject.toml
DocType扩展doc_eventsdoc_events推荐使用
extend_doctype_class
Python最低版本3.103.103.11
INI补丁
Fixtures格式JSONJSONJSON

v16 Breaking Changes

v16重大变更

  • extend_doctype_class
    hook: Cleaner DocType extension pattern
  • Data masking: Field-level privacy configuration available
  • UUID naming: New naming rule option for DocTypes
  • Chrome PDF: wkhtmltopdf deprecated for PDF generation

  • **
    extend_doctype_class
    **钩子:更简洁的DocType扩展模式
  • 数据掩码:支持字段级隐私配置
  • UUID命名:DocType新增命名规则选项
  • Chrome PDF:wkhtmltopdf已被弃用,改用Chrome生成PDF

Critical Implementation Rules

关键实施规则

✅ ALWAYS

✅ 必须遵守

  1. Start with
    bench new-app
    - Never create structure manually
  2. Define
    __version__
    in
    __init__.py
    - Build will fail without it
  3. Test patches on database copy - Never run untested patches on production
  4. Use batch processing - Any patch touching 1000+ records needs batching
  5. Filter fixtures - Never export all records of a DocType
  6. Version your patches - Use v1_0, v2_0 directories for organization
  1. 始终从
    bench new-app
    开始
    - 切勿手动创建应用结构
  2. __init__.py
    中定义
    __version__
    - 缺少此项构建会失败
  3. 在数据库副本上测试补丁 - 切勿在生产环境运行未测试的补丁
  4. 使用批量处理 - 任何涉及1000条以上记录的补丁都需要批量处理
  5. 过滤fixtures - 切勿导出某个DocType的所有记录
  6. 为补丁版本化 - 使用v1_0、v2_0目录进行组织

❌ NEVER

❌ 切勿执行

  1. Put frappe/erpnext in pyproject dependencies - They're not on PyPI
  2. Include transactional data in fixtures - Only configuration!
  3. Hardcode site-specific values - Use hooks or settings DocTypes
  4. Skip
    frappe.db.commit()
    in large patches
    - Memory will explode
  5. Delete fields without backup patch - Data loss is irreversible
  6. Modify core ERPNext files - Always use hooks or override patterns

  1. 在pyproject依赖中添加frappe/erpnext - 它们不在PyPI上
  2. 在fixtures中包含交易数据 - 仅包含配置数据!
  3. 硬编码特定站点的值 - 使用钩子或配置DocType
  4. 在大型补丁中跳过
    frappe.db.commit()
    - 会导致内存溢出
  5. 不做备份补丁就删除字段 - 数据丢失不可恢复
  6. 修改ERPNext核心文件 - 始终使用钩子或覆盖模式

Reference Files

参考文件

FileContents
references/decision-tree.md
Complete decision flowcharts
references/workflows.md
Step-by-step implementation guides
references/examples.md
Complete working examples
references/anti-patterns.md
Common mistakes to avoid

文件内容
references/decision-tree.md
完整的决策流程图
references/workflows.md
分步实施指南
references/examples.md
完整的工作示例
references/anti-patterns.md
需要避免的常见错误

See Also

另请参阅

  • erpnext-syntax-customapp
    - Exact syntax reference
  • erpnext-syntax-hooks
    - Hooks configuration
  • erpnext-impl-hooks
    - Hook implementation patterns
  • erpnext-database
    - Database operations for patches
  • erpnext-syntax-customapp
    - 具体语法参考
  • erpnext-syntax-hooks
    - 钩子配置
  • erpnext-impl-hooks
    - 钩子实施模式
  • erpnext-database
    - 补丁相关的数据库操作