跳到主要内容

Server Side

https://github.com/frappe/frappe/wiki/Developer-Cheatsheet

frappe module

frappe.form_dict

Request parameters

Form Dict: {'doctype': 'FIN Report Def', 'company': 'DTY007', 'is_group': '1', 'item_name': 'test003', 'parent': '流动资产', 'is_root': 'false', 'cmd': 'erpnextcn.fin.doctype.fin_report_def.fin_report_def.add_rc'}
frappe.get_doc(doctype, name)

e.g. frappe.get_doc('Project', 'My Project')

Load a document from the database with give doctype (table) and name Returns a Document object. All columns are properties. e.g. doc.name

frappe.get_meta(doctype)

Loads the metadata (DocType) of the given doctype.

e.g. frappe.get_meta('Task').fields is the list of fields in Task doctype

frappe.get_all(doctype, filters, fields)

e.g. frappe.get_all('Project', filters={'status': 'Open'}, fields=['name', 'description'])

Returns a list of dict objects from the database

frappe.get_list(doctype, filters, fields, order_by)

Sames as frappe.get_all, but will only show records permitted for the user

Allows sorting with the order_by parameter (optional). E.g. frappe.get_list('Payment Entry', filters={'docstatus': 0, 'payment_type': 'Pay'}, fields=['name', 'posting_date', 'paid_amount'], order_by='posting_date')

Note that the get_list command will return no more than 20 items by default. To increase this, use the limit_page_length parameter. Using the limit_start parameter allows to use pagination. In case the requested is a child table, do not forget to pass the parent parameter with the parent doctype to check permissions.

frappe.get_value(doctype, name, fieldname)

Return a single value from the database Example: frappe.get_value('Task', 'TASK00030', 'owner')

frappe.get_last_doc(doctype)

e.g. frappe.get_last_doc('Project')

Get last created document of this type.

frappe.get_single(doctype)

e.g. frappe.get_single('Dropbox Settings')

Return a frappe.model.document.Document object of the given Single doctype.`

frappe.get_installed_apps()

Returns a list of all the installed apps in the current site.

Document Object

Load a document
doc = frappe.get_doc(doctype, name)

# get properties
doc.title

# set properties to the document
doc.first_name = 'My Name'

# save a document to the database
doc.save()

Insert a new doc

doc = frappe.get_doc({
"doctype": "Project",
"title": "My new project",
"status": "Open"
})
doc.insert()

How to make public API

Add @frappe.whitelist() to the function

Example: say your app name is myapp, add this to api.py

@frappe.whitelist()
def get_last_project():
return frappe.get_all("Project", limit_page_length = 1)[0]

This will be accessible as /api/method/myapp.api.get_last_project. You can call it from js like this:

frappe.call({
method: "myapp.api.get_last_project",
callback: (response) => {
console.log(response.message);
}
});

Syntax Error

You may have noticed that sometimes if there is a syntax error in your Python code and you bench start, it fails without telling you why.

To find out the problem, run the following commands:

cd ~/frappe-bench/sites
../env/bin/python ../apps/frappe/frappe/utils/bench_helper.py

Hopefully, you will get the correct traceback to fix your error.


Client Side

Desk

Globals

  • cur_frm: Current form object
  • cur_list: Current list object
  • cur_dialog: Current open dialog
  • cur_page: Current page object
  • frappe.quick_entry: Current Quick Entry object.
  • locals: All documents and DocType loaded in the browser session. A document can be access as locals[doctype][name] e.g. locals['Opportunity']['OTY00001']

Routing

Routes for standard views:

  • #List/[doctype]
  • #Form/[doctype]/[name]
  • #Report/[doctype]
  • #Calendar/[doctype]
  • #Tree/[doctype]
  • #modules/[module name]
  • #activity
  • #Dashboard

To change the route via js, use frappe.set_route

frappe.set_route("List", "Customer");
Route Options

To pass values to a view, use global frappe.route_options. frappe.route_options is data passed to the view to whom control is being passed. For list view, it is a filter. For form, it is a default value.

Example:

frappe.set_route("List", "Customer", {"customer_type": "Company"});

or

frappe.route_options = {"customer_type": "Company"};
frappe.set_route("List", "Customer");

Forms

Form API

1. To add a new handler on value change.

Syntax

frappe.ui.form.on([DocType], {
[trigger]: function(frm) {
[function];
}
});

Replace [DocType] with the one you want to use, in quotations. Example:

frappe.ui.form.on("Sales Order", {

or

frappe.ui.form.on("Purchase Order", {

in the case of a child table, the function still calls the parent doctype.

Replace [Trigger] with the one you want to use. Example:

company: function(frm) {

This would trigger the function when the company field is modified or

onload: function(frm) {

This would trigger the function when the document is loaded.

List of Triggers

  • Field Names (see the company example above)
  • setup
  • onload
  • refresh
  • validate
  • on_submit
  • onload_post_render

What trigger is called when?

TriggerUser > ReloadF5Ctrl + Shift + RNew Document (first time)New Document (again)Menu > ReloadOpen document (first time)Open document (again)Save document
Refresh
Onload
Setup

Child Table Triggers

Child Table Triggers need to be on the subtable DocType.

  • fieldname_add
  • fieldname_move
  • before_fieldname_remove
  • fieldname_remove

Example:

frappe.ui.form.on("Salary Slip", {
company: function(frm) {
// this function is called when the value of company is changed.

}
});

Example for child table (e.g. in Sales Invoice custom script):

frappe.ui.form.on('Sales Invoice Item', {
items_add: function(frm) {
// adding a row ...
},
items_remove: function(frm) {
// removing a row ...
}
});

2. Adding Standard JS Listeners to form fields

Sometimes the built in triggers are not enough, so you can use standard JavaScript event listeners together with triggers to achieve better results. For a comprehensive list of listeners, check this site. The following example loads a listener once the document has been rendered and loaded. The listener runs some code when a key is pressed in the customer field.

frappe.ui.form.on("Sales Invoice", {
onload_post_render: function(frm) {
// This function is run right after a Sales Invoice is rendered and loaded

// This listener is added to the customer field, listening for a keypress event
cur_frm.fields_dict.customer.$input.on("keypress", function(evt){
// Code specified here will run when a key is pressed on the customer field.
});
}
});

3. Change value in the form

frm.set_value(fieldname, value);

4. Talk to the database

frappe.db.get_value(doctype, filters, fieldname, callback, parent_doc)
frappe.db.get_single_value(doctype, field)
frappe.db.get_doc(doctype, name, filters = null)
frappe.db.get_list(doctype, {fields: [], limit: 20})

// check if document already exists
frappe.db.exists(doctype, name)

// insert a new document:
frappe.db.insert({
doctype: 'Project',
project_name: 'Build a decent documentation',
expected_end_date: '2030-02-28'
})

frappe.db.delete_doc(doctype, name)
frappe.db.count(doctype, args={})

All are asynchronous and return a promise.

5. Add a new row to a child table

For example, add a new Task 'Update Developer Cheatsheet' to every new Project on load. (For a list of triggers, see above.)

frappe.ui.form.on("Project", {
onload: function (frm) {
if (frm.is_new()) {
frm.add_child('tasks').title = 'Update Developer Cheatsheet';
frm.refresh_field('tasks');
}
}
});
  • tasks is the name of the child table within Project
  • we need to run refresh_field for the new row to become visible
frappe.ui.form.on('{{ parent DocType }}', {
onload: function(frm) {
frm.set_query('{{ link field name }}', '{{ child table name }}', function() {
return {
'filters': {
'{{ field in linked doctype }}': ['{{ operator }}', '{{ value }}']
}
};
});
},
});

For example, consider this snippet from Web Page doctype. Web Page contains a child table named page_blocks, which contains a link field to Web Template. The following restricts the link query to show only Web Templates which are not of type "Component".

frappe.ui.form.on('Web Page', {
onload: function(frm) {
frm.set_query('web_template', 'page_blocks', function() {
return {
'filters': {
'type': ['!=', 'Component']
}
};
});
},
});

Running Tasks Serially

To run tasks serially, use frappe.run_serially

frappe.run_serially([
() => frappe.set_route('List', 'ToDo'),
() => frappe.new_doc('ToDo')
]);

Tests

To run individual test use

bench --site test-service run-tests --module erpnext.tests.test_woocommerce

Utility

To know list of Installed Apps of a Site