Skip to content

PRISM - Script

Client Side

Using ”frappe.call” with Various Built-in Methods

Using frappe.call in Frappe Javascript

  • Used to call backend (Python) methods from frontend (JavaScript)
  • Commonly used for accessing and updating data from the doctypes.

Command Syntax

frappe.call({
method: "<method_path>",
args: {
<arg_key>: <arg_value>
},
callback: function(ldResponse) {
console.log(ldResponse.message);
}
})

Using the frappe.client.get method with frappe.call – Fetch Full Document

  • Used to get a complete document using its name.
  • Helpful when you need all fields including child tables

Command Syntax

frappe.call({
method: "frappe.client.get",
args: {
doctype: "<doctype_name>",
name: "<doctype_id>"
},
callback: function(r) {
console.log(r.message);
}
});

Parameters & Options

ParameterTypeDescription
doctypestringDoctype Name (“Sales Order”)
namestringDocument ID (“SAL-ORD-2025-00015”)

Common Patterns or Use Cases

frappe.call({
method: "frappe.client.get",
args: {
doctype: "Sales Order",
name: "SAL-ORD-2025-00015"
},
callback: function(ldResponse) {
if(ldResponse.message) {
const ldDoc = ldResponse.message;
console.log("Customer:", ldDococ.customer);
console.log("Status:", ldDoc.status);
console.log("Items:", ldDoc.items);
}
}
});

Sample Output :

{
"name": "SAL-ORD-2025-00015",
"customer": "ABB AG",
"status": "To Deliver",
"items": [
{
"item_code": "DTTHZ2N 1200/10/400/6/75",
"qty": 1,
"rate": 10000
}
]
}

Using frappe.client.get_list with frappe.call – Fetch Filtered List of Documents with Specific Fields

  • frappe.client.get_list is used to retrieve a list of documents from a specific Doctype based on filters.
  • You can specify which fields to return and which records to include using filters.

Command Syntax

frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "<doctype_name>",
filters: { <field_name>: <value> },
fields: ["<field_name1>", "<field_name2>"]
},
callback: function(r) {
console.log(r.message);
}
});

Parameters & Options

ParameterTypeDescription
doctypestringDoctype (e.g., "Sales Order")
filtersobjectConditions to filter documents (e.g., { "status": "Draft" })
fieldsarraySpecific fields to return from the matching documents (e.g., ["name", "customer_name"])

Common Patterns or Use Cases

frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "Sales Order",
filters: { "name": "SAL-ORD-2025-00015" },
fields: ["customer_name"]
},
callback: function(ldResponse) {
if (ldResponse.message) {
const lCustomer = ldResponse.message;
console.log("Customer:", lCustomer);
}
}
});

Sample Output :

Customer: [{ customer_name: "Global" }]

Using the frappe.client.get_value method with frappe.call – Fetch Specific field

  • Used to retrieve only selected fields
  • Lightweight and faster for quick lookups

Command Syntax

frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "<doctype_name>",
filters: { name: "<doctype_id>" },
fieldname: ["<field_1>", "<field_2>"]
},
callback: function(ldResponse) {
console.log(ldResponse.message);
}
});

Parameters & Options

ParameterTypeDescription
doctypestringDoctype Name (“Sales Order”)
filtersobjectField-value pairs
fieldsstring/arrayOne or More fields

Common Patterns or Use Cases

Fetching only specific fields (e.g. customer, transaction_date)

frappe.call({
method: "frappe.client.get_value",
args: {
doctype: "Sales Order",
filters: { name: "SAL-ORD-2025-00015" }
fieldname: ["customer", "transaction_date"]
},
callback: function(ldResponse) {
if(ldResponse.message) {
const ldDoc = ldResponse.message;
console.log("Customer:", ldDococ.customer);
console.log("Transaction Date:", ldDoc.transaction_date);
}
}
});

Sample Output :

{
"customer": "ABB AG",
"transaction_date": "2025-05-28"
}

Using the frappe.db.get_value method – Fetch Specific Field(s) without fetching full document

  • Used to retrieve only selected fields from a document.
  • Lightweight and faster for quick lookups

Command Syntax

frappe.db.get_value(doctype, filters, fieldname, callback);

Parameters & Options

ParameterTypeDescription
doctypestringDoctype Name (“Sales Order”)
filtersobjectField-value pairs
fieldsstring/arrayOne or More fields
callbackfunctionprocess the response

Common Patterns or Use Cases

Fetching only specific fields (e.g. customer, transaction_date)

frappe.db.get_value(
"Sales Order",
{ name: "SAL-ORD-2025-00015" },
["customer", "transaction_date"],
function(ldResponse) {
if (ldResponse.message) {
const ldDoc = ldResponse.message;
console.log("Customer:", ldDoc.customer);
console.log("Transaction Date:", ldDoc.transaction_date);
}
}
);

Sample Output :

{
"customer": "ABB AG",
"transaction_date": "2025-05-28"
}

Using frm.call – Call Server-Side API Method from Client-Side

  • Used to call a Python API method from the client-side script.
  • Allows real-time interaction with backend logic, fetching data, or performing operations.

Command Syntax

frm.call({
method: "method.path", //api name: get_quote_from_salesorder
args: {
key1: value1,
key2: value2
},
callback: function(ldResponse) {
// handle response
}
});

Parameters & Options

ParameterTypeDescription
methodstringAPI method name (server-side script)
argsobjectArguments as key-value pairs
callbackfunctionresponse is received from the server

Common Patterns or Use Cases

frm.call({
method: "get_quote_from_salesorder", // API method name
args: {
source_name: frm.doc.name
},
callback: function(ldResponse) {
if (ldResponse.message) {
//code here
}
}
});

Using frappe.set_intro – Display an Introductory Message in a Form

  • Shows a small descriptive message at the top of the form.
  • Helps provide guidance or context to users filling the form.

Command Syntax

frappe.set_intro(message);

Parameters & Options

ParameterTypeDescription
messagestringDisplaying text

Common Patterns or Use Cases

frappe.ui.form.on('Sales Order', {
onload: function(frm) {
frm.set_intro("Set Intro at Top in Sales Order");
}
});

Sample Output : alt text

Using frappe.df.set_property – Set Properties Dynamically on DocField in a Form

  • Modify field properties such as reqd (mandatory), read_only, hidden, etc., dynamically.

Command Syntax

frappe.df.set_property(fieldname, property, value, frm);

Parameters & Options

ParameterTypeDescription
fieldnamestringFieldname
propertystringProperty to set (e.g., “reqd”, “hidden”)
valueboolean0 or 1
frmobjectForm object (usually passed as frm)

Common Patterns or Use Cases

frappe.ui.form.on('Sales Order', {
onload: function(frm) {
if (frm.doc.custom_factory === 'SGBCZ') {
frm.set_df_property('custom_factory', 'reqd', 1);
} else {
frm.set_df_property('custom_factory', 'reqd', 0);
}
}
});

Sample Output : alt text

Using frm.set_value – Set a Field Value in the Form

  • Used to set or update the value of a field programmatically.
  • Triggers related events like on_change, validation, and linked field logic.

Command Syntax

frm.set_value(fieldname, value);

or

frm.set_value({
fieldname1: value1,
fieldname2: value2
});

Parameters & Options

ParameterTypeDescription
fieldnamestringName of the field to update
valueanyNew value to set for the field

Common Patterns or Use Cases

frappe.ui.form.on('Quotation', {
refresh: function(frm) {
frm.set_value('project_name', 'Test Set Value');
//or
frm.set_value({
party_name: "ABC Corp",
company: "LMNAs Cloud Solutions" //hidden field
});
}
});

Sample Output : alt text

Using add_fetch – Auto Fetch Field Value from Linked Doctype

  • Automatically pulls a value from a linked document’s field and sets it in the current form.
  • Used in frappe.ui.form.on() to map one field to another when a link field is selected.

Command Syntax

frm.add_fetch(link_field, source_fieldname, target_fieldname);

Parameters & Options

ParameterTypeDescription
link_fieldstringLink field in the form
source_fieldnamestringField to fetch from the linked doctype
target_fieldnamestringField in the current form to set the value

Common Patterns or Use Cases

frappe.ui.form.on('Quotation', {
customer(frm) {
frm.add_fetch('party_name', 'll_packaging', 'packaging');
}
});

Sample Output : alt text

  • Used to define dynamic filters for Link fields at the field level.
  • Placed inside frappe.ui.form.on() for the specific field.
  • Returns filter conditions for dropdown value

Common Syntax

frm.fields_dict[fieldname].get_query = function(doc) {
return {
filters: {
key: value
}
};
};

Parameters & Options

ParameterTypeDescription
fieldnamestringName of the Link field to filter
docobjectCurrent form document context (frm.doc)
filtersobjectKey-value pairs used to filter link options

Common Patterns or Use Cases

frm.fields_dict['item_code'].get_query = function(doc) {
return {
filters: {
item_group: doc.item_group //item_group: 'DTTHZ2N'
}
};
};
  • Used to apply dynamic filters to Link fields.
  • Can be used for fields in the main form or in child tables.
  • More flexible than get_query.

Common Syntax

frm.set_query(fieldname, doctype, function(doc) {
return {
filters: {
key: value
}
};
});

Common Patterns or Use Cases

# Syntax for Parent form field
frappe.ui.form.on('Sales Order', {
setup: function(frm) {
frm.set_query('customer', null, function(doc) {
return {
filters: {
customer_group: 'Commercial'
}
};
});
}
});
// Syntax for Child form field
frappe.ui.form.on('Sales Order', {
setup: function(frm) {
frm.set_query('item_code', 'items', function(doc) {
return {
filters: {
item_group: 'DTTHZ2N'
}
};
});
}
});

Best Practice

  • Use set_query in the setup event.
  • Use get_query only if you want to write the filter directly on the field.
  • Avoid hardcoding values unless they are fixed.

Using frappe.model.with_doc – Access a Full Document in the Client Script

  • frappe.model.with_doc is used to fetch and access the complete document from the database by specifying its doctype and name.
  • Useful when you want to use values from another document that is not currently open in the form.

Command Syntax

frappe.model.with_doc(doctype, name).then(doc => {
// code here
});

Parameters & Options

ParameterTypeDescription
doctypestringName of the Doctype to fetch
namestringThe unique name (ID) of the document

Common Patterns or Use Cases

frappe.ui.form.on('Quotation', {
onload: function(frm) {
if (frm.doc.party_name) {
frappe.model.with_doc('Customer', frm.doc.party_name).then(ldCustomerDoc => {
frappe.msgprint(`Customer Territory: ${ldCustomerDoc.territory}`);
});
}
}
});

Sample Output : alt text

Using frappe.model.set_value – Set the Value of a Field in a Child Doctype Row

  • Sets or updates the value of a specific field in a child table row.
  • Useful for dynamically updating fields inside child tables based on conditions or user input.

Command Syntax

frappe.model.set_value(doctype, docname, fieldname, value);

Parameters & Options

ParameterTypeDescription
doctypestringName of the Child DocType
docnamestringName of the child document (child row)
fieldnamestringField name whose value you want to set
valueanyThe value to set for the field

Common Patterns or Use Cases

frappe.ui.form.on('Sales Order', {
refresh: function(frm) {
// Set the 'status' field to 'Draft' on form refresh
frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'status', 'Draft');
// Set rate of first item in items table to 1000
if (frm.doc.items && frm.doc.items.length > 0) {
let ld_first_item = frm.doc.items[0];
frappe.model.set_value(ld_first_item.doctype, ld_first_item.name, 'rate', 1000);
}
}
});

Using HTML Templates in JavaScript – Render Dynamic HTML with JS

  • Helps inject structured HTML layouts (like tables, cards, alerts) dynamically in Frappe forms or pages.
  • Useful for rendering data-driven UI like logs, summaries, or visual indicators.

Pre-requiste You need to have a field of type HTML

Command Syntax

const ldTemplate = `<div>...</div>`;
frappe.render_template(ldTemplate, { key: value });

Parameters & Options

ParameterTypeDescription
templatestringInline HTML template string using Jinja-style tags
keystringName of the param object used in the template
valueobjectContext variables used for rendering the template (parameter used in the jinja)

Notes & Best Practices

  • Frappe uses a microtemplate engine, not full Jinja — it’s based on John Resig’s lightweight JavaScript templating system, commonly referred to as Resig-style templates.
  • Loops and variables must follow Frappe’s JS microtemplate syntax:
    • Use {% for(var i = 0; i < array.length; i++) { %} for loops
    • Use {%= array[i].field %} to render values
  • Standard Jinja syntax like {% for item in items %} is not supported in client scripts and will not work.
  • Avoid using single quotes ' inside the HTML template string — always use double quotes " to avoid syntax issues.
  • It’s best practice to set rendered HTML using:
    frm.set_df_property("fieldname", "options", html);
    frm.refresh_field("fieldname");

Common Patterns or Use Cases

Show a visual summary of lead or opportunity status transitions (e.g., Open → Contacted → Quoted), helping users quickly understand progress.

frappe.ui.form.on('Lead', {
onload(frm) {
const laStatusLog = [
{
status_from: "Open",
status_to: "Contacted",
timestamp: "2025-06-01 10:00:00",
duration: "2 days"
},
{
status_from: "Contacted",
status_to: "Quoted",
timestamp: "2025-06-03 15:30:00",
duration: "1 day 5 hrs"
}
];
const ldTimelineTemplate = `
<div class="form-grid-container">
<div class="form-grid">
<div class="grid-heading-row">
<div class="grid-row">
<div class="data-row row">
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">Status From</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">Status To</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">Timestamp</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">Time Difference</div></div>
</div>
</div>
</div>
<div class="grid-body">
<div class="rows">
{% for(var i = 0; i < status_log.length; i++) { %}
<div class="grid-row">
<div class="data-row row">
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">{%= status_log[i].status_from %}</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">{%= status_log[i].status_to %}</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">{%= status_log[i].timestamp %}</div></div>
<div class="col grid-static-col col-xs-3"><div class="static-area ellipsis">{%= status_log[i].duration %}</div></div>
</div>
</div>
{% } %}
{% if (!status_log.length) { %}
<div class="grid-row">
<div class="data-row row">
<div class="col text-muted" colspan="4">No status log found.</div>
</div>
</div>
{% } %}
</div>
</div>
</div>
</div>
`;
const ldHtml = frappe.render_template(ldTimelineTemplate, { status_log: laStatusLog });
frm.set_df_property("custom_html_field", "options", ldHtml )
frm.refresh_field('custom_html_field');
}
});

Sample Output : alt text

JavaScript Array Methods

1. forEach() – Loop through Sales Order Items

Description: Iterates over each item in the items array and performs an operation (e.g. log details or compute amount).

Common Syntax

laArray.forEach(function(ldItem, lIndex) {
//code here
});

Parameters & Options:

ParameterTypeDescription
ldItemobjectcurrent item from the array
lIndexnumberIndex of the current item

Use Cases

A company sells equipment, and each item in a Sales Order Item has its qty. We want to calculate the total qty of all items and show it in a custom field total_qty on the Sales Order form.

We will use forEach() to iterate over the items table and add up the individual warranty months.

let lTotalQty = 0;
frm.doc.items.forEach(ldItem => {
if (ldItem.qty) {
lTotalQty = lTotalQty + ldItem.qty;
}
});
// Set the total in a custom field on the main form
frm.set_value('total_qty', lTotalQty);

2. map() – Transform Sales Order Items

Description: Returns a new array by transforming each item in the list (e.g. extract item codes).

Common Syntax

const laResult = laArray.map(function(ldItem) {
return transformedValue;
});

Parameters & Options:

ParameterTypeDescription
ldItemobjectcurrent item from the array

Use Cases

You want to list all item_codes from the sales order to display in a summary section.

const LAitemCodes = salesOrder.items.map(function(ldItem) {
return ldItem.item_code;
});
console.log("Item Codes:", LAitemCodes);

Sample Output

Item Codes: ["DTTHZ2N 1200/10/400/6/75", "DTTHZ2N 800/10/400/6/50"]

3.find() – Find First Matching Item

Description: Returns the first item that matches a condition (e.g. first bulk item).

Common Syntax:

const LAresult = laArray.find(function(ldItem) {
return condition;
});

Parameters & Options:

ParameterTypeDescription
ldItemobjectcurrent item from the array

Use Cases

A sales rep is creating a Sales Order. The system should check if a specific promotional item (e.g., item_code: “PROMO-123”) is included — to apply special pricing or show a reminder.

let lPromoItem = frm.doc.items.find(idItem => idItem.item_code === "PROMO-123");
if (lPromoItem) {
frappe.msgprint("You’ve added the promotional item! Don’t forget to apply the special discount.");
}

Sample Output

A popup message displaying "You’ve added the promotional item! Don’t forget to apply the special discount."

4. filter() – Filter Matching Items

Description: Returns a new array with all items that match the condition (e.g. expensive items).

Common Syntax:

const LDresult = laArray.filter(function(ldItem) {
return condition;
});

Parameters & Options:

ParameterTypeDescription
ldItemobjectcurrent item from the array

Use Cases

You want to extract all items that belong to the item group “Transformers” to apply some logic — for example warranty rules.

let laTransformerItems = frm.doc.items.filter(item => item.item_group === 'Transformers');
// You can now use laTransformerItems for further logic
console.log("Transformer Items:", laTransformerItems);
laTransformerItems.forEach(ldItem => {
ldItem.warranty_months = 24; // Set a default warranty
});

5. reduce() – Calculate Total Value

Description: Reduces the array to a single value (e.g. total sales order amount).

Common Syntax:

const LDresult = laArray.reduce(function(lAccumulator, ldItem) {
return updatedAccumulator;
}, lInitialValue);

Parameters & Options:

ParameterTypeDescription
lAccumulatornumbertotal/result
ldItemobjectCurrent item in the array
lInitialValuenumberStarting value (e.g. 0)

Use Cases

You want to calculate the total value of a Sales Order for quote submission.

//Calculate total amount of sales order
const LtotalAmount = salesOrder.items.reduce(function(lAcc, ldItem) {
return lAcc + ldItem.qty * ldItem.rate;
}, 0);
console.log("Total Sales Order Amount:", LtotalAmount);

Sample Output:

Total Sales Order Amount: 27000

JavaScript Child Table

Accessing All Rows in a Child Table

Description: Access all rows (documents) inside the items child table.

Common Syntax

const laChildRows = frm.doc.items;
laChildRows.forEach(function(ldRow, lIndex) {
// perform operations
});

Parameters & Options:

ParameterTypeDescription
laChildRowsarrayArray of child table rows
ldRowobjectCurrent row in the child table
lIndexnumberIndex of the current row

Common Patterns or Use Cases

frm.doc.items.forEach(function(ldRow, lIndex) {
console.log(`Item ${lIndex + 1}:`, ldRow.item_code);
});

Sample Output:

Item 1: DTTHZ2N 1200/10/400/6/75 Item 2: DTTHZ2N 800/10/400/6/50

Adding a New Row to Child Table

Description: Programmatically adds a new row to the items table.

Common Syntax:

let lNewRow = frm.add_child("items");
lNewRow.item_code = "DTTHZ2N 2000/12/440/6/75";
frm.refresh_field("items");
ParameterTypeDescription
frmobjectCurrent form instance
lNewRowobjectNewly added child table row

Common Patterns or Use Cases

const lNewRow = frm.add_child("items");
lNewRow.item_code = "DTTHZ2N 2000/12/440/6/75";
lNewRow.qty = 2;
lNewRow.rate = 150;
frm.refresh_field("items");

Sample Output: A new row appears in the child table with DTTHZ2N 2000/12/440/6/75.

Accessing Specific Row by cdt and cdn

Use locals[cdt][cdn] to access or update a specific row in a child table — typically within child table event handlers like fielname, {fieldname}_add, etc.

Common Syntax

let lRow = locals[cdt][cdn];
console.log(lRow.item_code);
ParameterTypeDescription
cdtstringChild Doctype
cdnstringUnique row identifier
localsobjectLocal model holding all doc data

Common Patterns or Use Cases

frappe.ui.form.on("Sales Order Item", {
rate(frm, cdt, cdn) {
let ldRow = locals[cdt][cdn];
if (ldRow.qty === 0) {
ldRow.qty = 1;
frm.refresh_field("items"); //items is the field name of child table in parent doctype
}
}
});

Sample Output:

Row is updated to quantity 1.

Where This Is Applicable

ScenarioUse cdt & cdn?Explanation
Inside frappe.ui.form.on("Child Doctype", { ... })YesYou get cdt & cdn as arguments to access the row
Inside on_change, on_add, on_remove for child tableYesIdeal for updating specific fields in the row
Inside parent Doctype events like refresh, validateNoUse frm.doc.items instead (an array of rows)

Modifying Child Table Field Properties

Description: Dynamically change a child table column’s properties like reqd, hidden, or read_only.

Common Syntax

frm.fields_dict["items"].grid.update_docfield_property("item_code", "read_only", 1);
frm.fields_dict["items"].grid.refresh();
ParameterTypeDescription
item_codestringFieldname in the child table
read_onlystringProperty to update
1 / 0booleanValue of the updated property

Common Patterns or Use Cases

frm.fields_dict["items"].grid.update_docfield_property("rate", "reqd", 1);
frm.fields_dict["items"].grid.refresh();

Sample Output:

The rate column in child table becomes mandatory.

Clear or Set Options in a Field in Child Table

Description: Clear or dynamically change dropdown options for a child table field.

Common Syntax

frappe.meta.get_docfield("Sales Order Item", "item_group", frm.docname).options = "";
ParameterTypeDescription
Sales Order ItemstringChild doctype name
item_groupstringField in the child table
frm.docnamestringName of the parent document

Common Patterns or Use Cases

frappe.meta.get_docfield("Sales Order Item", "item_group", frm.docname).options = "DTTH2n\nDOTML";
frm.fields_dict["items"].grid.refresh();

Sample Output:

Dropdown list for item_group is updated.

Get value of password field

When used get_value() for password field, the return value is asterisk(encrypted), so use get_password method to retrieve the actual value of password type field

Basic Syntax in client

frappe.call({
"method": "frappe.client.get_password",
"args":{
"doctype": <doctype_name>
"name": <document_name>
"fieldName": <field_name>
}
})

Common Use Cases

  • getting the open api key from raven settings doctype
frappe.call({
"method": "frappe.client.get_password",
"args":{
"doctype": "Raven Settings,
"name": "Raven Settings", //single doctype
"fieldName": "openai_api_key"
}
"callback": function(idResponse){
if(idResponse.message){
console.log("open api key", idResponse.message)
}
}
})

Sample Output

open api key fhryryfhghgus8ghffgfhffjfjgjreg

Using frappe.client.get_list with frappe.call – For accessing the child table

  • Specify which fields to return
  • Select which records to include using filters

Command Syntax

frappe.call({
method: 'frappe.client.get_list',
args: {
doctype: '<Child Table Doctype>',
parent: '<Parent Doctype>',
filters: { parent: '<Parent Document Name>' },
fields: ['<Field1>', '<Field2>'] // specify fields you want to retrieve
},
callback: function(response) {
// handle the response here
console.log(response.message);
}
});

Parameters & Options

ParameterTypeDescription
doctypestringThe Doctype to retrieve records from (e.g., "Sales Order")
filtersobjectConditions to filter the records (e.g., { "status": "Draft" })
fieldsarrayList of fields to retrieve from each document (e.g., ["name", "status"])

Common Patterns or Use Cases for (Child Table)

  • Automatically fetch all organizations linked to that Git user.

  • Show them in a message or set them in another field.

frappe.call({
method: 'frappe.client.get_list',
args: {
doctype: 'Git User Organizations', // Child Table Doctype
parent: 'Git User', // Parent Doctype
filters: { parent: frm.doc.custom_git_username }, // Parent Document Name
fields: ['git_organization'] // Fields to Retrieve
},
callback: function(r) {
if (r.message && r.message.length > 0) {
// Example: Set the first organization name in a form field
frm.set_value('organization_name', response.message[0].git_organization);
}
}
});

Server Side

frappe.get_doc in server side

Returns a document object for the given doctype and name, if no document match throw “DoesNotExistError”. Note: for single doctype, name is not required

Basic Syntax

frappe.get_doc(<doctype_name>, <document_name>)

Common Use Case

ld_task = frappe.get_doc("Task", "TASK-0023")
frappe.msgprint(str(ld_task.title)) //ex: title is Cpq Documentation

Sample Output

Cpq Documentation

For single doctype

ld_system_setting = frappe.get_doc("System Setting")
frappe.msgprint(str(ld_system_setting.theme)) //ex: theme is dark

Sample Output

dark

Using frappe.get_all – Fetch Multiple Records from a Doctype

  • Retrieves a list of records from a specific DocType.
  • Returns a list of dictionaries with selected fields (or just names if no fields specified).
  • Lightweight and efficient – ideal for read-only queries.
  • Useful for querying main table fields and child table fields.

Command Syntax

frappe.get_all(doctype, filters=None, fields=None, limit=None, order_by=None)

Parameters & Options:

ParameterTypeDescription
doctypestringName of the DocType to fetch records from.
filtersdict/listList of specified fields to fetch
limitintLimits number of results. Optional.
order_bystringSort order (e.g., “creation desc”). Optional.

Common Pattern or Use Cases

la_orders = frappe.get_all(
'Sales Order',
filters={'customer': 'ABB AG'},
fields=['name', 'transaction_date'],
order_by='transaction_date desc',
limit=5
)

or

# Get customer from current document
l_customer_name = doc.customer # e.g., "ABB AG"
# Fetch Sales Orders with fields from main and child tables
la_sales_orders = frappe.get_list(
"Sales Order",
filters={"customer": l_customer_name},
fields=[
"name",
"customer",
"territory",
# Sales Order Item (Child Table)
"`tabSales Order Item`.item_code",
"`tabSales Order Item`.qty",
"`tabSales Order Item`.rate"
]
order_by="transaction_date desc",
limit=10
)
# Display each Sales Order with child item details
for ld_so in la_sales_orders:
frappe.msgprint(f"""
SO: {ld_so.name} | Customer: {ld_so.customer}
Item: {ld_so.item_code} | Qty: {ld_so.qty} | Rate: {ld_so.rate}
""")

Sample Output:

[{'name': 'SAL-ORD-2025-00014', 'transaction_date': datetime.date(2025, 5, 29)},
{'name': 'SAL-ORD-2025-00010', 'transaction_date': datetime.date(2025, 2, 18)},
{'name': 'SAL-ORD-2025-00011', 'transaction_date': datetime.date(2025, 2, 18)},
{'name': 'SAL-ORD-2025-00008', 'transaction_date': datetime.date(2025, 2, 5)},
{'name': 'SAL-ORD-2025-00007', 'transaction_date': datetime.date(2025, 2, 4)}]

Using frappe.get_list – Fetch Records from a Doctype (Server Script)

  • Retrieves a list of records from a specified doctype.
  • Supports filtering, sorting, field selection, and limits.
  • Commonly used in server scripts to extract data based on conditions.

Command Syntax

frappe.get_list(doctype, filters=None, fields=None, order_by=None, limit=None)

Parameters & Options:

ParameterTypeDescription
doctypestringName of the DocType to fetch records from.
filtersdict/listList of specified fields to fetch
limitintLimits number of results. Optional.
order_bystringSort order (e.g., “creation desc”). Optional.

Common Pattern or Use Cases

# Get customer from current document
l_customer_name = doc.customer # l_customer_name = "ABB AG"
# Fetch Sales Orders for this customer
la_sales_orders = frappe.get_list(
"Sales Order",
filters={"customer": l_customer_name},
fields=["name", "transaction_date", "grand_total"],
order_by="transaction_date desc"
)
# Display each Sales Order
for ld_so in la_sales_orders:
frappe.msgprint(f"Sales Order: {ld_so.name} | Date: {ld_so.transaction_date} | Total: ₹{ld_so.grand_total}")

Sample Output:

Sales Order: SAL-ORD-2024-0003 | Date: 2024-12-01 | Total: ₹75,000
Sales Order: SAL-ORD-2024-0022 | Date: 2024-10-15 | Total: ₹52,000
Sales Order: SAL-ORD-2025-0001 | Date: 2025-08-30 | Total: ₹19,500

frappe.get_all vs frappe.get_list

frappe.get_allfrappe.get_list
Faster; optimized for raw data accessSlightly slower due to permission and hook handling
Does not check permissions by defaultChecks user permissions by default
Skips get_list hooksRuns get_list hooks if defined
Only fetches database (DocType) fieldsCan fetch custom fields and computed properties
Cannot access child tables or property settersCan access child tables and custom properties
Best for internal scripts and background jobsBest for user-facing features and API responses
Supports filters, fields, limit, and order_bySupports filters, fields, limit, and order_by
Use ignore_permissions=True to override accessAutomatically respects permissions
Does not load DocType metadataLoads and applies DocType metadata
Lightweight and fastMore feature-rich and secure

Using doc.save() – Save a Document on the Server Side

  • Saves the document to the database.
  • Triggers validations and standard lifecycle events like before_save, validate, on_update, and after_save.

Command Syntax

doc.save()

Common Pattern or Use Cases

# Create and save a new document
ld_sales_order = frappe.new_doc("Sales Order")
ld_sales_order.customer = "Test Customer"
ld_sales_order.append("items", {
"item_code": "DTTHZ2N/1000/22/440/6/95",
"qty": 2
})
ld_sales_order.save()

Sample Output:

{
"name": "SO-0004",
"doctype": "Sales Order",
"customer": "Test Customer",
"delivery_date": "2025-06-20",
"items": [
{
"item_code": "DTTHZ2N/1000/22/440/6/95",
"qty": 2,
"doctype": "Sales Order Item",
"parent": "SO-0004",
"parenttype": "Sales Order",
"parentfield": "items"
}
]
}

Best Practice (doc.save())

Avoid ThisWhy It Matters
doc.save(ignore_permissions=True)It skips permission checks. This can cause security issues. Use it only when really needed.
Calling doc.save() inside a loopIt runs validations and writes to the database many times. This makes the code slow. Save once after the loop.

Using doc.insert() – Insert a New Document into the Database

  • Inserts a brand-new document into the database.
  • Used only for new records (not for updates).
  • Triggers standard lifecycle events like before_insert, validate, and after_insert.

Command Syntax

doc.insert()

Common Pattern or Use Cases

ld_customer = frappe.new_doc("Customer")
ld_customer.customer_name = "Test User"
ld_customer.customer_group = "Commercial"
ld_customer.territory = "India"
ld_customer.insert()

Sample Output:

{
"name": "TEST USER",
"doctype": "Customer",
"customer_name": "Test User",
"customer_group": "Commercial",
"territory": "India",
}

Doctype’s MetaData

use get_meta to get specific Doctype’s information along with the custom field and property setter

Basic Syntax This method can only be used on Server Side

frappe.get_meta('<doctype_name>')

Common Use Cases

ld_ToDo_meta = frappe.get_meta("ToDo")
frappe.msgprint(str(ld_ToDo_meta.fields)) #printing the meta information of the fields
#Note: str() should be used to flaten the object, otherwise it will be printed as [Object][Object]

Sample Output

{
"message": [
{
"name": "jv5ncgrirp",
"docstatus": 0,
"parent": "ToDo",
"parentfield": "fields",
"parenttype": "DocType",
"idx": 1,
"fieldname": "description_and_status",
"fieldtype": "Section Break",
"hidden": 0,
.......},
{
"name": "jv511449u4",
"docstatus": 0,
"parent": "ToDo",
"parentfield": "fields",
"parenttype": "DocType",
"idx": 2,
"fieldname": "status",
"label": "Status",
"fieldtype": "Select",
"options": "Open\nClosed\nCancelled",
....},
....
]}

CPQ CheatSheet

Setting a watch flag for a field

In client script you use fieldName(frm) to implement onChange of specific field. similarly, you can achieve the same in vue js using watch() Note: only use it on core, not on CRM Form Script

Basic Syntax

watch(fieldName, (NewValue, OldValue) =>{
//your logic
}
{ immediate: false } //to avoid initial undefined error onmount
)

Common Use Cases

  • On Change of tabs from Activity to Note,
watch(tabs, (CurrentTab, PreviousTab) => {
//using watch we can access previous and current value of the field
console.log("previous selected tab", PreviousTab)
console.log("current selected tab", CurrentTab)
}
{immediate: false}
)

Sample Output

previous selected tab Activity
current selected tab Note

Custom Button in CPQ

use CRM Form Script (client script for CPQ) to add custom button in the both ListView or Individual View

Pre-requisite Go to CRM Form Script, create a new CRM Form Script with Name “Custom Button”, Doctype: “CRM Deal”, Apply To: “Form” and enable the script

Basic Syntax

action:[{"label": <label>, "onClick": () => {//your logic}
}]

Common Use Cases

  • Create a View Quotation button on Deal
function setupForm({ doc }) {
return {
action:[{"label": "View Quotation", "onClick": () => {console.log("The button "View Quotation" is clicked")}
}]
}
}

Sample Output

  • Open the Existing Deal Document, you will see the “View Quotation” button at top right corner
  • On clicking the “View Quotation” button
//in browser console
The button "View Quotation" is clicked

To navigate between pages like from Deal to Quotation in CPQ using a Frappe form script, you can use router() which is similar to set_route() in frappe

Pre-requisite Include the router param in the setupForm function

Basic Syntax

router.push({"name": <doctype_name>, "params": {"name": <id>}
})

Common Use Cases

  • navigate to the quotation created for the Specific Deal (ex: CRM-DEAL-0003)
function setupForm({ doc, router }) {
return {
action[{
"label": "View Quotation",
"onClick": () => {
router.push({"name": "Quotation", "params": {"name": doc.custom_quotation_id}
})
}
}]
}
}

Sample Output On clicking the View Quotation button in the CRM-DEAL-0003 will take you to the Quotation

ref in Vue js

Use ref() to create a value, where Vue wraps it in a reactive object so it can track changes and trigger updates in the UI when used in templates.

Pre-requisite

import { ref } from 'vue'

Basic Syntax

ref(<intial_value>)
//`intial_value` can be any type: number, string, boolean, array, object, etc.

**Common Use Cases **

<template>
<Button
:label="__('Create')"
:loading="IsLoading" //When you use a `ref` variable in the template, Vue automatically unwraps `.value`, so you can use it directly.
@click="fnHandleClick" />
</template>
<script setup>
const IsLoading = ref(false)
function fnHandleClick(){
IsLoading.value = true //To access or update it: use `.value`
.....
//after successfull created
IsLoading.value = false
}
</script>

Sample Output When you clicked the “Create” button an spinner animation appear, after successfully creation, the button come back to normal

reactive in Vue.js

  • reactive() makes an object “watchable” so Vue knows when its data changes.
  • the difference between ref() and reactive() is that reactive only work with object or array, so you can’t use it for single primitive like reactive(5) or reactive(false)

Pre-requisite

import { reactive } from 'vue'

Basic Syntax

reactive({
"name":"",
"items":[]
})

**Common Use Cases **

<template>
<FormControl
:label="__('Design Template')"
type="text"
:placeholder="design_template"
@change="(value)=> fnHandleUpdate("design_template", value)"
/>
</template>
<script setup>
const Design = reactive({"design_template":"", "direct_material": ""})
function fnHandleUpdate(iField, iValue){
Design[iField] = iValue
console.log(`${iField} is set to ${iValue}`)
}
</script>

Sample Output

Design Template is set to Step Up

Frappe Resource API

createResource() from frappe-ui is an build in reactive object that is used for async data fetching and processing with build in loading state, cache, error handling and watcher Pre-requisite

import { createResource } from 'frappe-ui'

Basic Syntax

createResource({
url: <method_path>,
params: {<filters, fields>},
cache: ['<cache_name>', <variable_of_createResouce>],
auto: true,
onSuccess(data){}, //on successful response
transform(data){}, //transform data before setting it
onError(error){}, //error can occur from failed request and validate function
makeParams(){}, //generate params from function
validate(params){}, //validate parameters before making request
})

**Common Use Cases **

const LaFieldLayout = createResource({
url: "crm.fcrm.doctype.crm_fields_layout.crm_fields_layout.get_fields_layout",
params:{ doctype: "Item", type: "Quick Entry"},
cache: ["tabs", LaFieldLayout],
auto: true,
onSuccess(iaTabs){
//the return structure of this endpoint will be like
//[{secions:[columns:[fields:[fieldName: "", fieldType: ""]]]}, {}]
iaTabs.forEach((idTab) => {
idTab.sections.forEach((idSection) => {
idSection.columns.forEach((idColumn) => {
idColumn.fields.forEach((idField) => {
if(idField.fieldType == "Table"){
console.log("Field name", idField.fieldName)
}
})
})
})
})
}
})

Sample Output

Field name Item Attribute

Classes and Objects

Constructor

A constructor is a special method in a class that gets called automatically when a new instance of the class is created. It is used to initialize the object with values or set up initial logic.Basic Syntax:

class ClassName {
constructor(parameter1: Type, parameter2: Type) {
// Initialization code here
}
}

You can access the constructor via the new keyword:

const obj = new ClassName(value1, value2);

Use Case We use constructors in base and derived classes to pass and initialize shared data like action and actionData.

class clActionOnLoad extends clAction {
constructor(iAction: string, iaActionData: TTactionsData) {
super(iAction, iaActionData); // Calls the constructor of the base class
}
// overrides and method calls
}

WHY

  • You pass data like action and actionData to the base class once.
  • You avoid repeating initialization logic in every subclass.
  • Subclasses can still add their own logic after calling super().

Interface

An interface is a syntactic contract that defines the structure of an object or class. It ensures that a class or object adheres to a particular shape by specifying what properties and methods it must have.Basic Syntax:

interface InterfaceName {
propertyName: type;
methodName(): returnType;
}

Use Case: We use the interface in the types.ts file to define the structure that any class or object must follow. In this case, the ifActionHandler interface acts as a contract for all action handlers, ensuring they have the necessary properties and methods.

interface ifActionHandler {
action: string;
actionData: TTactionsData;
actionRow: TactionData;
executeAction(): void;
checkFieldValue(): void;
checkFieldProperties(): void;
dataType: ifDataType;
}

Use this interface in an abstract class:

abstract class abstract class clAction implements ifActionHandler {
// Must implement all properties and methods from the interface
}

WHY:

  • By using the interface in the types.ts, you define a standard structure for all actions.
  • Every class that implements this interface will be forced to follow that structure.
  • This helps in maintaining consistency, improving type safety, and enabling scalable code architecture.

Factory class

Use a factory class when you need to dynamically create instances of different classes based on a runtime condition (e.g., a string key), without hardcoding class instantiations.Use Case: Dynamically create and return the correct clAction subclass based on the action type string at runtime (e.g., "Onload", "Add Row", etc.).

// Factory class to create action instances dynamically based on action type
class clActionFactory {
private static actionsMap: {
[key: string]: new (iAction: string, iaActionData: TTactionsData) => clAction
} = {
"Onload": clActionOnLoad,
"On Change": clActionOnChange,
"On Tab": clActionOnTab,
"Add Row": clActionAddRow,
"Edit Details": clActionEditDetails,
"Expand Section": clActionExpandSection,
};
// Factory method to return the correct action class instance at runtime
static createAction(
type: string, // Action type string (e.g., "Add Row")
iAction: string,
iaActionData: TTactionsData
): clAction {
const ActionClass = this.actionsMap[type];
if (!ActionClass) {
throw new Error(`Action type '${type}' is not registered.`);
}
// Return a new instance of the action class
return new ActionClass(iAction, iaActionData);
}
}
  • Easily create instances of different classes based on a string key without hardcoding logic.
  • Easily register new actions by adding to actionsMap
  • Keeps instantiation logic centralized.