erpnext-syntax-clientscripts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ERPNext Client Scripts Syntax (EN)

ERPNext客户端脚本语法指南

Client Scripts run in the browser and control all UI interactions in ERPNext/Frappe. They are created via Setup → Client Script or in custom apps under
public/js/
.
Version: v14/v15/v16 compatible (unless noted otherwise)
客户端脚本运行在浏览器中,控制ERPNext/Frappe中的所有UI交互。可通过设置 → 客户端脚本创建,或在自定义应用的
public/js/
目录下创建。
版本兼容: v14/v15/v16(除非另有说明)

Quick Reference

快速参考

Basic Structure

基本结构

javascript
frappe.ui.form.on('DocType Name', {
    // Form-level events
    setup(frm) { },
    refresh(frm) { },
    validate(frm) { },
    
    // Field change events
    fieldname(frm) { }
});
javascript
frappe.ui.form.on('DocType Name', {
    // 表单级事件
    setup(frm) { },
    refresh(frm) { },
    validate(frm) { },
    
    // 字段变更事件
    fieldname(frm) { }
});

Most Used Patterns

常用代码模式

ActionCode
Set value
frm.set_value('field', value)
Hide field
frm.toggle_display('field', false)
Make field mandatory
frm.toggle_reqd('field', true)
Call server
frappe.call({method: 'path.to.method', args: {}})
Prevent save
frappe.throw('Error message')
操作代码
设置字段值
frm.set_value('field', value)
隐藏字段
frm.toggle_display('field', false)
设置字段为必填
frm.toggle_reqd('field', true)
调用服务器方法
frappe.call({method: 'path.to.method', args: {}})
阻止保存
frappe.throw('Error message')

Event Selection

事件选择

Which event should I use?
One-time setup (queries, defaults)?
└── setup

Show/hide UI, add buttons?
└── refresh

Validation before save?
└── validate

Do something right after save?
└── after_save

React to field change?
└── {fieldname}
→ See references/events.md for complete event list and execution order.
应该使用哪个事件?
一次性初始化(查询、默认值设置)?
└── setup

显示/隐藏UI、添加按钮?
└── refresh

保存前验证?
└── validate

保存后执行操作?
└── after_save

响应字段变更?
└── {fieldname}
→ 完整事件列表及执行顺序请参考 references/events.md

Essential Methods

核心方法

Value Manipulation

值操作

javascript
// Set single value (async, returns Promise)
frm.set_value('status', 'Approved');

// Set multiple values at once
frm.set_value({
    status: 'Approved',
    priority: 'High'
});

// Get value
let value = frm.doc.fieldname;
javascript
// 设置单个值(异步,返回Promise)
frm.set_value('status', 'Approved');

// 批量设置多个值
frm.set_value({
    status: 'Approved',
    priority: 'High'
});

// 获取值
let value = frm.doc.fieldname;

Field Properties

字段属性

javascript
// Show/hide
frm.toggle_display('priority', condition);

// Make mandatory
frm.toggle_reqd('due_date', true);

// Make read-only
frm.toggle_enable('amount', false);

// Advanced property change
frm.set_df_property('status', 'options', ['New', 'Open', 'Closed']);
frm.set_df_property('amount', 'read_only', 1);
javascript
// 显示/隐藏字段
frm.toggle_display('priority', condition);

// 设置为必填字段
frm.toggle_reqd('due_date', true);

// 设置为只读
frm.toggle_enable('amount', false);

// 高级属性修改
frm.set_df_property('status', 'options', ['New', 'Open', 'Closed']);
frm.set_df_property('amount', 'read_only', 1);

Link Field Filters

链接字段筛选

javascript
// Simple filter
frm.set_query('customer', () => ({
    filters: { disabled: 0 }
}));

// Filter in child table
frm.set_query('item_code', 'items', (doc, cdt, cdn) => ({
    filters: { is_sales_item: 1 }
}));
→ See references/methods.md for complete method signatures.
javascript
// 简单筛选
frm.set_query('customer', () => ({
    filters: { disabled: 0 }
}));

// 子表格中的字段筛选
frm.set_query('item_code', 'items', (doc, cdt, cdn) => ({
    filters: { is_sales_item: 1 }
}));
→ 完整方法签名请参考 references/methods.md

Server Communication

服务器通信

frappe.call (Whitelisted Methods)

frappe.call(调用白名单方法)

javascript
frappe.call({
    method: 'myapp.api.process_data',
    args: { customer: frm.doc.customer },
    freeze: true,
    freeze_message: __('Processing...'),
    callback: (r) => {
        if (r.message) {
            frm.set_value('result', r.message);
        }
    }
});
javascript
frappe.call({
    method: 'myapp.api.process_data',
    args: { customer: frm.doc.customer },
    freeze: true,
    freeze_message: __('Processing...'),
    callback: (r) => {
        if (r.message) {
            frm.set_value('result', r.message);
        }
    }
});

frm.call (Document Methods)

frm.call(调用文档控制器方法)

javascript
// Calls method on document controller
frm.call('calculate_taxes', { include_shipping: true })
    .then(r => frm.reload_doc());
javascript
// 调用文档控制器中的方法
frm.call('calculate_taxes', { include_shipping: true })
    .then(r => frm.reload_doc());

Async/Await Pattern

Async/Await 模式

javascript
async function fetchData(frm) {
    let r = await frappe.call({
        method: 'frappe.client.get_value',
        args: {
            doctype: 'Customer',
            filters: { name: frm.doc.customer },
            fieldname: 'credit_limit'
        }
    });
    return r.message.credit_limit;
}
javascript
async function fetchData(frm) {
    let r = await frappe.call({
        method: 'frappe.client.get_value',
        args: {
            doctype: 'Customer',
            filters: { name: frm.doc.customer },
            fieldname: 'credit_limit'
        }
    });
    return r.message.credit_limit;
}

Child Table Handling

子表格处理

Adding Rows

添加行

javascript
let row = frm.add_child('items', {
    item_code: 'ITEM-001',
    qty: 5,
    rate: 100
});
frm.refresh_field('items');  // REQUIRED after modification
javascript
let row = frm.add_child('items', {
    item_code: 'ITEM-001',
    qty: 5,
    rate: 100
});
frm.refresh_field('items');  // 修改后必须调用此方法

Editing Rows

编辑行

javascript
frm.doc.items.forEach((row) => {
    if (row.qty > 10) {
        row.discount_percentage = 5;
    }
});
frm.refresh_field('items');
javascript
frm.doc.items.forEach((row) => {
    if (row.qty > 10) {
        row.discount_percentage = 5;
    }
});
frm.refresh_field('items');

Child Table Events

子表格事件

javascript
frappe.ui.form.on('Sales Invoice Item', {
    qty(frm, cdt, cdn) {
        let row = frappe.get_doc(cdt, cdn);
        frappe.model.set_value(cdt, cdn, 'amount', row.qty * row.rate);
    },
    
    items_add(frm, cdt, cdn) {
        // New row added
    },
    
    items_remove(frm) {
        // Row removed
    }
});
→ See references/examples.md for complete child table examples.
javascript
frappe.ui.form.on('Sales Invoice Item', {
    qty(frm, cdt, cdn) {
        let row = frappe.get_doc(cdt, cdn);
        frappe.model.set_value(cdt, cdn, 'amount', row.qty * row.rate);
    },
    
    items_add(frm, cdt, cdn) {
        // 新增行时触发
    },
    
    items_remove(frm) {
        // 删除行时触发
    }
});
→ 完整子表格示例请参考 references/examples.md

Custom Buttons

自定义按钮

javascript
frappe.ui.form.on('Sales Order', {
    refresh(frm) {
        if (frm.doc.docstatus === 1) {
            // Grouped buttons
            frm.add_custom_button(__('Invoice'), () => {
                // action
            }, __('Create'));
            
            // Primary action
            frm.page.set_primary_action(__('Process'), () => {
                frm.call('process').then(() => frm.reload_doc());
            });
        }
    }
});
javascript
frappe.ui.form.on('Sales Order', {
    refresh(frm) {
        if (frm.doc.docstatus === 1) {
            // 分组按钮
            frm.add_custom_button(__('Invoice'), () => {
                // 执行操作
            }, __('Create'));
            
            // 主要操作按钮
            frm.page.set_primary_action(__('Process'), () => {
                frm.call('process').then(() => frm.reload_doc());
            });
        }
    }
});

Critical Rules

重要规则

  1. ALWAYS call
    frm.refresh_field('table')
    after child table modifications
  2. NEVER use
    frm.doc.field = value
    — use
    frm.set_value()
  3. ALWAYS use
    __('text')
    for translatable strings
  4. validate event: use
    frappe.throw()
    to prevent save
  5. setup event: only for one-time configuration (not repeated)
→ See references/anti-patterns.md for common mistakes.
  1. 务必在修改子表格后调用
    frm.refresh_field('table')
  2. 禁止直接使用
    frm.doc.field = value
    ,请使用
    frm.set_value()
  3. 务必使用
    __('text')
    处理可翻译字符串
  4. validate事件:使用
    frappe.throw()
    阻止保存
  5. setup事件:仅用于一次性配置(不会重复执行)
→ 常见错误示例请参考 references/anti-patterns.md

Related Skills

相关技能

  • erpnext-impl-clientscripts
    — Implementation workflows and decision trees
  • erpnext-errors-clientscripts
    — Error handling patterns
  • erpnext-syntax-whitelisted
    — Server-side methods to call
  • erpnext-impl-clientscripts
    — 实现工作流与决策树
  • erpnext-errors-clientscripts
    — 错误处理模式
  • erpnext-syntax-whitelisted
    — 可调用的服务器端方法