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 objectcur_list
: Current list objectcur_dialog
: Current open dialogcur_page
: Current page objectfrappe.quick_entry
: Current Quick Entry object.locals
: All documents and DocType loaded in the browser session. A document can be access aslocals[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?
Trigger | User > Reload | F5 | Ctrl + Shift + R | New Document (first time) | New Document (again) | Menu > Reload | Open 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 withinProject
- we need to run
refresh_field
for the new row to become visible
Filter link options in a child table
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