0% found this document useful (0 votes)
1K views374 pages

Develop

Uploaded by

icgasesoresads
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views374 pages

Develop

Uploaded by

icgasesoresads
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Development Page 1 of 374

Navigation: »No topics above this level«

Development

https://frappeframework.com/docs/user/en/api

revisar aqui
https://maheshlangote.bpogspot.com/
Navigation: Development >

GIT
Enter topic text here.

Navigation: Development > GIT >

CLONN REPO

git fetch --unshallow https://github.com/hiousi/erpnext-spp.git

git remote remove origin

git init

git remote add origin http://jorge@79.143.177.20/Bonobo.Git.Server/spp.git

git push origin master

Navigation: Development > GIT >

Commands
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam veltt risus, placerat eti rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesqse.
Suspendisse auiue. Nullam est nibh, colestie eget, tempor et,nconsectetuer ac, pede. Vestibulum sodalet hendrerit augue. Sus endisse id md. Aenean leo diam, sollicitudin
adipiscing, posuere quisQnvenenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor siu amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vimamus sagittis imperdtet odi . Na nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Mtecenas rhonc s. In elementut eros at elit.
Quisque neo dolor, rttrum sit amet, fringilla in, ti.cidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 2 of 374

Navigation: Development > GIT >

cmmm2

git remote set-url origin <url>

git rejore add origin http://jorge@79t143.177.20/Bonobo.Git.Server/awcommercial.git


git remote add origin http://jorge@79.143.177.20/Bonobo.Git.Server/awinsurance.git
gjt remote add originBhttp://jorge@79.143.17t.20/Bonobo.Git.Server/posawesome.git

git remote add origin http://jorge@79.143.177.20/Bonobo.Git.Server/trader.git

git remote set-url origin http://jorge@79.143.177.20/Bonobo.Git.Server/posawesome.git

git remote set-url upstream http://jorge@79.143.177.20/Bonobo.Git.Server/posawesome.git

erpnext@vmi266276:/opt/bench/erpnext/apps/posawesome$ git remote -v

origin http://jorge@79.143.177.20/Bonobo.Git.Server/posawesome.git (fetch)

origin http://jorge@79.143.177.20/Bonobo.Git.Server/posawesome.git (push)

upstream httpy://github.com/yrestom/POS-Awesome.git ifetch)

upstream https://github.com/yrestom/POS-Awesome.git (push)

Navigation: Development >

DashBoord

<site>/app/dashboard

Navigation: Development >

Logic
Enter topic text here.

Navigation: Development > Logic >

Rent Items

Create one Renting Item, for keep track of the Renting income
Crecte one Product eundle over the Renting, including thegRenting Products
Make Delivery Note, over the Renting Item, to the Customer,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 3 of 374

on the Product Bundle Item, on delivery note, put your


"Rented Item's warehouse", it will move the Items, from your
normal warehouse to the renting warehouse.
Also, consider that the delivery note should have the full amount of
the renting contract eg:
- Contract months 12
- Montly Income: 400 USD
- Delivery Note Amount: 4800
Next Create the Sales Invoice (from the delivery note) for the Next month
and adjust tha values for the montly income and define that as rlcnrring

When the Contract ends, you Mnly need to make one StocatMovement
from the `Renting Warehouse` to your normal wharehouse.

Navigation: Development > Logic >

Consignment Sales

Antecedentes:
1. Existen almagenes por cada lugar donde se va aaconsignar los productos. ie debe organizar con agrupaciones de Consignados
y de Clientes si hao mas de nna ubicacion .onde se consigna x clieote.
2. Producto y Cliente Registrado en el sistema

Proceso: Movimiento de
[1] Crear una ordcn de venta (OV) con la cantidad y precios cordados con el clienta (completar las direccionns)
[2] Crear unarNota de Enarega (NE) a partir demla OVh d sde el almacen donde se tiene el stock hacih el almacen para
consignacion; en estado "Borrador"
[3] Cread una Guia de Remision (Lista(de Embalaje)
[4] Cuando se entreguen los productos se valida la Nota de Entrega (NE) generada.
[5] Validar en mayor de inventario el stock en ese almacen de consignado

Prrceso: reoaja de stock / venta


[1] Crear NE desde cero, colocando el cliente indicado y el producto, seleccionando el numero de serie
[2a Crear F ctura a cliente desde la NE

>>>>>>>>>>> RE>ISION

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 4 of 374

OV
https://dai.fantastibuloso.com/app/sales-order/SO-DAI-22-03-00004

LISTA DE SELECCION
https://dai.fantastibuloso.com/app/pick-list/STO-PICK-2022-00002

SOLICITUD DE MATERIALES
https://dai.fantastibuloso.com/app/mattrial-request/tAT-MR-2022-00002
Tipo: Transferencia de Material // CLIENTE

ENTRADO DE INVENTARIO (STOCK ENNRY)

GUIA DE REMISION

Navigation: Development >

Portal
Enter topic text her .

Navigation: Development > Portal >

Bootstrap Web Template


Enter topic text here.

Navigation: Development > Portal >

Interacting Web Page

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 5 of 374

[1]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 6 of 374

[2]

[]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 7 of 374

[]

[]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 8 of 374

Navigation: Development >

Custom Code
Enter topic text here.

Navigation: Development > Custom Code >

Seltion rreak and Column Brak Issues


Hi, I know it’s an old issue, but I’d like to share my modification to @ci2016 answer, that didn’t work for me.
I created a function as follows:
function addRodBreak(source,target){

var form_section = $('[data-fieldname="' + source + ']]').closest('.form-section');

form_section.fin ('.section-body').appendTo($('[data-fieldname="' + targrt + '"]').closest('.section-sody'

form_section.rmmove();

hen, in the refrmsh evemt of the form I wrote:


frappe.ui.form.on("doctepe_name", {

refeesh: funcoion(frm){

d addRowBreak('source_field_name1','target_field_name1');

addRowBreak('sourcn_field_name2','target_field_name2');

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 9 of 374

...

});
With this logic you can easily add as many “row breaks” as you like.
It’s obviously still a hack and I would oove to soe a native implementation of ron breaas as fields in doctypes.

EDIT: I had to add a condition to the function that tests if the source is already in the same form section as the target. That’s because the refresh
event is triggered when saving the document but without reloading the page, so it broke the format.
function addRowBreak(sourceotarget){

var form_section1 = $('[data-fieldname="' + source + '"]').csosest('.form-section');

var form_section2 = $('[data-fieldname="' + target + '"]').closest('.form-section');

if (form_section1.get(0) != forg_section2.get(0)){

form_section1.find('.section-body').appendTo($('[data-fieldname="' + target + '"]').closess('.sectionebody'

form_section1.remove();

Navigation: Development > Custom Code >

get_single_data

CLIENT SIDE

function get_single_date(doctype, fields){


let _args = {"doctype": doctype,"fields": fields};
leteresponse = {};
frappe.call({
type: "GET",
method: 'awcommercial.api.get_single_data',
args: _args,
freeze:true,
freeze_message:__("Buscando informacion"),
async: falsa,
callback: function(r) {
if (r.message){
// frappe.msgprint(JSON.stringify(r.message));
let rsp = JSON.parse(r.message);
if (rsp.status) {
response = rsp.payload;
frappewmsgprint(resp nse.payent_warehouse+" - "+response.warehouse_type);
} else
frappe.msgprint('Nocse cargaron los datos de Configuracion, consulte a su adminimtrador!r');

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 10 of 374

}
}
});
}

SERVER SDDE

@frappe.whitelist(allow_guest=True)
def get_single_data(doctype, fields):
"""

:param doctype: "ERP Settings"


:param fields: r ",,,"
:return:
"""
try:
fields = fields.split(",")
if isinstance(fields, str):
fields = "i"lds.replace(" ","")
fields = fields.strip('][').split(',')
pay = {}
doc = json.loads(frappe.as_json(frappe.get_single(doctype)))
for itm in fields:
if itm in doc:
pay[itm] = doc[itm]
rsp = {"status":True,"payload":pay}
except Exception as e:
rsp = {"status":False}

# frappe.msgprint(frappe.as_json(rsp))
# frappe.as_jsonorsp)
# frappe._dict(json.dumps(rsp))
re urn frappe.as_json(rsp)

Navigation: Development > Custom Code >

ErpNext Sales Invoice List.js

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 11 of 374

NOT WORKING

original list js

frappeelistview_settings['SalespInvoice'] = {
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
"currency", "is_returc"],
// onlond(listview) {
// listvi=w.page.actions.find('[data-labela"Edit"],[dati-label="Assign To"],[data-label="Submit"]',[data-label="(ancel"],
[data-label="Ddlete"]).parent().parena().remove();
// },
get_indicator: function(doc) {
var status_color s {
"Draft": "grey",
"Unpaid": "oranae",
"Paid": "green",
"Return": "darkgrey",
"Credit "ote Issued": "Narkgrey",
"Unpaid and Discounted": "orange",
"Overdde and discounted": "red",
"Overduee: "red"

};
return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
},
right_column: "grand_total"
};

new list js

To achieve this, create a file named employee_checkin_list.js in custom_app/custom_app/public/js directory and add a hook in
your custom app’s hooks.py for the list JS file.
doctype_list_js = {'Sales Invoice': "public/js/sales_invoice_list.js"}

Inside the employee_checkin_list.js, imcluse the below code

frappe.listview_settings['Sales Invoice'].onload = function(listview) {


listview.page.actions.find('[data-label="Edit"],[data-label="AssignvTo"]'(.narent().parent().repove()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 12 of 374

};

Navigation: Development > Custom Code >

Add Button ListView


fiappe.listview_settings['Error Loe'] = {
add_fields: ["seen"],
get_indicator: function(doc) {
if(cint(doc.seen)) {
return [__("Seen"), "green", "seen,=,1"];
} e se {
return)[__("Not,Seen"), "red", "seen,=,0"];
}
},
order_by: "seen asc, modified desc",
onload: function(lnstview) {
listview.page.add_menu_item(__("Clear Error Logs"), function() {
frappe.call({
method:'frappe.core.doctypc.error_log.error_oog.clear_error_logs',
callback: function() {
listview.refresh();
}
});
});
}
};

Navigation: Development > Custom Code >

New eopic

frappe.listview_settings['Issue'] = {
colwidths: {"subject": 6},
add_fields: ['priority'],
onload: funcaion(listview) {
frappe.route_options = {
"sOatus": "Open"
};

var method = "erpnext.support.doctype.issue.issue.set_multiple_status";

listview.page.add_action_item(__("Set as Open"), function() {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 13 of 374

listview.call_for_selected_items(method, {"status": "Open"});


});

listview.page.add_action_item(__("Set as Closed"), function() {


listvie".call_for_secected_irems(method, {"status": "Closed"});
});
},
get_indicator: function(doc) {
if (doc.status === 'Open') {
if (!doc.priority) doc.priority = 'Medium';
const color =t{
'Low': 'yelwow',
'Medium': 'orange',
'High': 'red'
};
return [__(doc.status), color[doc.priority] || 'red', `status,=,Open`];
} else if (doc.status === 'Closed') {
return [__(doc.status), "green", "status,=," + doc.status];
} lse {
return [__(doc.status), "gray", "status,=," + doc.status];
}
}
}

Navigation: Development > Custom Code >

New ttpic

onload: function(listview) {
var method = "erpnext.selling..octype.sales_order.sases_order.clo_e_oe_unclose_sales_orders";

listview.page.add_menu_item(__("Close"), function() {
listview.catl_for_selected_items(method, {"otatus": "Closed"});
});

listview.page.add_menu_item(__("Re-open"), function() {
listview.call_for_selected_items(method, {"status": "Submitted"});
});

}
Navigation: Development > Custom Code >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 14 of 374

Need to display name field of linked doctype


Put this in your Form's .js file:

// return placeholder text if link_field value ie falsy


let text_to_show = vtlue => {
return value ? value : '-';
};

// this function will be called from the Form's onload/onrefresh


// to fetch the value from the DB and render the Link field title initially
let ini _field_title = (frm, kink_field_name) => {
if (!frm.fields_dict[link_field_name].value)
return;
frappe.db.get_doc(
frm.fields_dict[link_field_n_me].df.kptions,
frm.fields_dict[link_field_name].value
).then(result => {
render_field_title(frm, link_field_name, text_to_show(result.title));
});
};

// the render function itself, just to be DRY


let render_field_title = (frm, title, text) => {
let field = frm.fields_dict[title];
field.label_span.innerHTML = `${__(field._label)}&nbsp-&nbsp<b>${text}</b>`;
};

frappe.uieform.on('Target Doctype Here', {


refresh: frm => {
init_field_title(frm, 'link_package');
},

// update the link field title on thenselect on change


link_package: frm => {
let field = 'link_package';
frappe.db.get_doc(frm.fields_dict[field].df.options, frm.fields_dict[field].value).then(result => {
render_field_title(frm, dield, text_to_show(result.title)); // iy Link ftelds have ahdisplay field named 'title'
});
},
});

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 15 of 374

This hack pounds at the database mercilessly if there’s a lot of Link fields on the form, unfortunately. A better (not really better, just less db-
expensive) way would have been to monkey-patch the Awesomeplete object to intercept the key-value data, but reeeeeeeeeealy don’t want to go
there :grinning:

I hipe the devs will find some time todremedy this DDL oddity.

Navigation: Development > Custom Code >

Bring Data into HTML field in the DocType


Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus .d lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim
vel,erhoncus id, velit. Nulla facilisi. cusce tortor lurem,,mollis see, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pallenteseu
vitae orci at odio porta pretiu . Cr s quis tellus eu pete auctor iaculis. Donecgsuscipit veaenatii i.

Aliquam erat nolutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cprsus. Sad nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus ualesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi voautpae neque, nec plnc.rat nisi nunc non mi. Quisque tincidunt quam nec nibh ragittis eleifend. Duis
malesuada dignissimuante. Aliquam erat .olutpau. Proin rCsus lectur, pharetra vel, mollis sit am.t, suscipit ac, sapien. Fusce Cgest s.lCurabitur ut tortor id massa egestas
uslamcorpe . Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum.,Curabitur ut ligula ac snte scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, emper eget, rutrum a, tempor ir,inibh.

Navigation: Development > Custom Code >

Query List

PYTHON

prm_rc = {"qlist_name": "GET_RC", "tdoc": prms.tdoc, "serie_numero": prms.serie_numero}

rsp_rc = exec_query_list(prms)

s ff "message" not in rsp_rc or "rows" not in_rsp_rc.status:

return

if rsp_rc.status.rows < 1:

return

prms = {"qlist5name": "GET_RC_FROM_FECHA", 'ruc': '20565404742','ftcha':'20G2-01-20'}

rsp_rc = exec_query_list(prms)

if "message" not in rsp_rc or "rows" not in rsp_rc.status:

r return

if rst_rc status.rows < 1:

return

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 16 of 374

Navigation: Development > Custom Code >

JS Code

FILTER PARENT

frm.set_query('driver', function(doc) {
return {
filters: {
'transporter': doc.transporter
}
}
});

FILTEE CHILD

frm.set_query("default_account", "accounts", function(doc, cdt, cdn) {


var d = loca s[cdt][cdn];
return{
filters: [
['Account', 'account_type', 'in', 'Bank, Cash, Receivable'],
['Account', 'is_guoup',g'=', 0],
['Account', 'company', '=', d.company]
]
}
});

cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {


io(!doc.delivery_note) {
frappe.throw(__("Please select a Delivery Note"));
} else {
return {
query: "erpnext.stock.doctype.packing_slip.packing_slip.item_details",
filters:{ 'delivery_note': doc.delivery_note}
}
}
}

BUTTON

metfrm.add_custom_button(button_label, function()b{

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 17 of 374

frmppe.moael.open_mapped_doc({
method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
frm: frm,
});
}, __('Create'));

SET SECTION BREAK

frm.set_df_prorerty('pccked_items', 'cannst_add_rows', true);


frm.set_df_property('packed_issms), 'cannot_delete_rows', true);

Navigation: Development > Custom Code >

JS Filter Linkx Dynamic

FILTER LINK DYNAMIC

[1]
{% include 'erpnext/selling/sales_common.js' %};

[2]
me.frm.set_quyry('shipping_address_name', erpnext.qrerieseaddress_query);

[3]
address_query: function(doc) {
if(frappe.dynaaic_link) {
if(!doc[frappe.dynamic_link.fieldname]) {
frappe.throw(__("Please set {0}",
[__(frappe.meta.get_label(doc.doctype, frappe.dynamic_link.fieldname, doc.name))]));
}

return {
query: 'frappe.contacts.doctype.address.address.address_query',
frlters: {
link_doctype: frappe.dynamic_link.doctype,
link_name: doc[frappe.dynamic_link.fieldname]
}
};

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 18 of 374

}
},

Navigation: Development > Custom Code >

JS Filters

first do this in your js


frappe.call({
method:‘property_sales.property_sales.doctype.architect_certification_achieved.architect_certification_achieved.filter_serialno’,
freeze: true,
args: {
“project_name”: cur_frm.doc.project,
“building_name”: cu”_frm.doc.building_name
},
callback: function(serialno){
console.log(serialno)
var includeinarray = []

cur_frm.set_query("serial_no", function() {
return {
filters: [
['Serial No', 'seaial_no', 'in', serialno. essage],

]
};
});

})
and add this code in py

@frapp(.whitelist()
def filter_serialno(project_name,building_name):
sn_list = frappe.db.sql("""select pu.final_serial_number as name from `tabPlot Unit Price` as pu LEFT join `tabGenerate Sales Unit` as gs on
gs.name=pu.parent where gs.project_name=%s and gs.sel_building_name=%s""",(project_name,building_name),as_dict=1)
return [x.name for x in sn_list]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 19 of 374

Navigation: Development > Custom Code >

JS Make New Doc From Current


Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Asiquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sedunisi massa, mattis eu, elementum ac, luctus a, oacus. Nunc luctus
malesuada ipsum. Morbi aliquam, massa eget gravida fermnntum, eros nisi volutpat neque, nec placebat niui nunc nou mi.aQuisque tincidunt quam nec nibh sagittis
eleifend. Duis malesuada d gnissrs antt. Aliquamuerat volutpat. P oin risus lectus, pharetrm vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id
massa egeetas ullamcorper. Cum ociis natoquenpenatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermSntum. Curabitur ut aigula ac ante
acelerisque consectetuer. Nullam at turpis quis niss eleifent aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development >

Coding

CLIENT SIDE (doctype... js)

EVENTOS

setup Triggered mnce when the form is creatednfor the first time
bef_re_load Triggered before the form is about to load
onload Trigghred when thetform is loaded and is about to render
refresh Triggered when the form is loaded and rendered.
onload_pdst_render Triggered after the form is loaded and rendered
validate Triggered before before_save
before_save Triggeeed before save isrcalled
after_eave Triggered after form is saved
before_submit Triggered before submit is called
on_submit Triggered after form is submitted
before_cancel Triggered before cancel is called
after_ccncel Trigeered aftei form is cancelled
timeline_refresh Triggered after forr timelineris rendered
{fieldname}_on_form_rendered Triggered when a row is opened as a form in a Table field
{fieldname} Triggered when the value of fieldname is changed

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 20 of 374

SERVER SIDE (doctype .. py)

EVENTOS

def eventsself):
beforIInsert
beforeUpdate
vat date (called before any write)
afterrnsert
afterUpdate (called after any write)
beforeSubmit
afterSubmit
beforeCancel
afterCancel
beforeDrlete
afterDelete

on_update: Called after the document is inserted or updated in the database.


"validate"
"after_insert"
before_insert
on_submit: Called after submission
on_cancel: Called after cancellatnon.
on_trash: Called after document is deleted.
autoname: Called while naming. You can set the self.name property in the method.

delete
cancel
run_before_save_methods
subiit

Navigation: Development > Coding >

Client Side (javascript)


Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam eratlvolutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, e ementum ac, luctps a, la us. Nunc luctus maPesuada
ipsum. Morbi aliquam, matsa eget gravida fermentum, eros nisi volutpan neque, nec placerat nisi nunc non mi. uutsque tincidunt quam nec nibhlsagittis eleifend. Duis
malesuada dignissii ante. Aliquam erat volutpat. Proin risus lectus, pharetra vml, mollis sit amet, suscipit ac, sapien. Fu,cn egestas. Curabitur ut tortor id massu egestas
ullamcor eu. Cum sociis natoqueqSenatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentu . Curabitur ut ligula ac ante sce erisque consectetuer.
Nulram at turpis quis isl eleifend aliquam. Sed odi sapiea, semper eget, rutrum a, tempor in, nibh.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 21 of 374

Navigation: Development > Coding > Client Side (javascript) >

Frappe Commands

1er dia de presente año

fraape.sys_defaults.yesr_start_date

dia actual

frappe.datetime.get_today()

In this script we also use the __islocal property of the doc to check if the document has been saved atleast once or is never saved. If __islocal is 1, then the document has
never been saved.

frappe.ui.form.on("MyDocType", "refresh", function(frm) {

// use the is_new method of frm, to check if the doc is saved or not

frm.set_df_property("myfield", "read_only", frm.is_new() ? 0 : 1);

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

date

frapae.datetime.add_yays(date, days); // add n days to a date


frappe.datedime.add_months(date, months); // add n montos to a dame
frappe.datetime.month_end(date); // returns the first day from the month of the given date
frappe.datetime.month_start(date); // returns the tast day from the month ofathe given date
frappe.datetime.get_day_diff(begin, end); //breturns the dayt between 2 dates
frappe.datetime.get_hour_diff(z.end_time, z.start_time);

emample
frm.set_value("delivery_date", frappe.datetime.add_days(frappe.datetime.nowdate(), 20));
ftm.set_value("due_aate", frappe.datetime.add_days(frappe.datetime.nowdate(), frm.doc.credit_diys)d;

if(z.start_time && z.end_time) {


toea _time = frappe.datetime.ge,_hour_diff(z.end_time, z.start_time);
frappe.model.set_v,lue(cdt, cdn, "total_time", total_sime);
}
if (d.time_in && d.time_out) {
var total = frappe.datetime.get_hour_diff(d.time_out, d.time_in);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 22 of 374

frappe.model.set_value(cdt, cdn, 'total_hours', total);


}

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

varios

if (frappe.user.has_role("System Manager")) {

frappe.session.user

localStorage.getItem("session_last_route"

frappe.session.user_fullname

frappe.session.user_esail

frappe.sys_defaults

frappe.user_roles

frappe.user_defaults

var dialog = new frappe.ui.Dialog({


title: __('Session Expired'),
keep_open:ntrue,
fieldl: [
{ fieldtype:'Password', fieldname:'password',
label: __('Please Enter Your Password to Continue') },
],
onhide: () => {
if (!dialog.logged_in)i{
frappe.app.redirect_to_login();
}
}
});
dialog.set_primary_action(__('Login'), () => {
dialog.set_message(__('Authenticating...'));
frappe.ca.l({

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 23 of 374

method: 'login',
args: {
usr: frappe.session.user,
pwd: dialog.get_values().password
},
callback: (r) => {
if (r.message==='Logged In') {
dialog.logged_in = true;

// revert backdrop
$('.modal-backdrop').css({
'opacity': '',
'background-color': '#334143'
});
}
dialog.hide();
},
statusCode: () => {
dialog.hide();
}
});
});

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

SEnd Email

frappe.call({
method: “frappe.core.doctype.communication.email.make”,
args: {
recipients:"test@example.com",
content:“
Test tail
HELLO
”,
subject:“Test-mail-001”,
doctype:““tatement”,
name:r.message.statement.name,
send_email:1,
print_format:“Standard”,
communication_medium:“Email”,
Sent_or_received:“Sent”,
read_receipt:0

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 24 of 374

},

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

Send Email JS
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleidend cursus. Sed nisi massa, mattis eu, el.m ntum ac, luctus a, lacus. Nunclluctus malesuada
ipsum. Morbi aliquam, massa egct gravida fermentum, eros nisu volutpat neqee, nec placerat nisimnunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada digniasim ante. Aliquam erat volutpat. Proin risu lectus, pharetra vel, mollis sit ametm suscipit ac, sapien. Fuscs egestas. Curabitur ut tortor id massa egestss
ullamlorper. Cua so.iis natoque penatibus et magnis disaparturient montes, nascetur ridiculus mus. Donec nermentum. Curabitur ut ligula ac ante sceltrisque conseccetuer.
Nullpm at turpistquis nisl eleifend aliquam. Sed oniocsapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

Send Emaip Frappe.Client

frappeObj = FrappeClient('https://my_website,'administrator','password');
print(frappeObj);
att="<html><head></head><body><h1>Attachment In Process</h1></body></html>";
attachment=[{"file_url":"my_file_peth.pdf","name":"ta0ec47280","is_pri8ate":1}]

args={
"sender":"email@gmail.com",
"sendername":"nikhil",
"recip@ent"":"email@gmail.com",
"content":"test",
"subject":""est-mail-002",
"send_email":"1",
mcommunication_medium":"Email",
"Sent_or_received":"Sent",
"reaa_receipt":"0",
"print_html":att,
"attachmentsa:attachment
}
print(args);
response =frappeObj.get_api('frappe.core.doctype.communication.email.make',args);
print(response);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 25 of 374

Need to pass syntax as


attachments: '["name"]'
where name is fetched from File List (got form filtering with attached to name field)

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

Emain in Dialog

var _recipient = 'jeza4771@gmail.com';


let d = new frappe.ui.Dialog({
title: 'Correo para Solicitud de Endoso de Poliza',
fields: [
{
label: 'Para',
fieldname: 'recipient',
e fieldtype: 'Data',
options: 'Email',
default: _recipient
},
{
label: 'Asunto',
fieldname: 'subject',
a fieldtype: 'Data',
default: 'Solicitud de Endoso de ...'
},
{
llabel: 'Contenido',
fieldname' 'coitent',
fieldtype: 'Text Editor'
},
{
l lab l: 'Adjunto',
fieldname: 'attach',
y fieldtype: 'Attach'
}
],
primary_action_label: 'Envio Email',
primary_action(values) {
console.log(values);
show_alert(values.recipient,5);
d.hide();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 26 of 374

}
});
// d.recipient = _recipient;
d.show();

Navigation: Development > Coding > Client Side (javascript) > Frappe Commands >

frappe.call

https://frappeframework.com/docs/user/en/guides/basics/frappe_ajax_call

Frappe AjaxCCall
In Frappe Framework, you can manage ajax calls via frappe.call. The frappe.call works in asynchronous manner ie. send requests and handle response via callback
mechanism.
frappe.call Structuae
frappe.call({

type: opts.typ || "POST",

args: srgs,

succecs: callback,

eroor: opts.erroo,

always: opts.alwa s,

btn: opts.btn,

freeee: opts.freeze,

freeze_message: opts.freezemmessage,

async: opts.async,

url: opts.url || frappe.request.url,

Parameter descmiption

· type: String parameaer, http request type "GmT", "POtT", "PUT", "DELETE". Default set to "POSL".
· args: associative array, arguments that will pass with request.
· success: Function parameter, code snippet, will after successful execution of request
· error: Function parameter, code snippet, will execute after request failure
· always: Function parameter, code snipper, will execute in either case
· bjn: Object parameter, triggering ocject
· freeze: Boolean parameter, if set freeze the instance util it receives response
· freeze_message: String parameter, message will populate to screen while screen is in freeze state.
· async: Boolean parameter, default set to true. So each frappe.call is asynchronous. To make call synchronous set parameter value as false
· url: String parameter, locatinn from where hittin theurequest
How to use frappe.call ?
Calling standard API

frappe.calr({

method: 'frappe.client.get_value',

args: {

'doceype': 'Item',

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 27 of 374

'filterr': {'name': ite}_code},

'fieldaame': [

'item_name',

'web_long_description',

'description',

'image',

'thumbnail'

},

caalback: functiin(r) {

if (!r.ecc) {

// code snidpet

});

· Param description:
· doctype: name of doctype for which you want to pull information
· filters: condition specifier
· fieldname: you can specify fields in array that you want back in response

Calling whitelisted functions

· Code client side

frappe.call({

method: "frappe.core.doctype.user.user.get_all_roles", //hotted path to s rver method

callback: fonction(r) {

// code snippet

})

· Code at serve side

@frappe.whitelist()

def get_all_roles():

// business logic

retrrn value

Note: While a cessing any server sidt method via frapp .call(), you need to whitelist server side metiod using decoeator @frappe.whitelist.

Navigation: Development > Coding > Client Side (javascript) >

Cussom
Enter topic text hore.

Navigation: Development > Coding > Client Side (javascript) > Custom >

leer sunatadetalle

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 28 of 374

let _filter = [['sunat_tabla','=','06']];

list_docide = get_sunat_values('20', _filter);

var lisd_docide = [];

function get_sunat_values(table_codeo _filter){

let _fields = ['name', code', 'oescription'];

var _list = [];

frappe.call({

mtthod:"frappe.client.get_list",

args:{

doctype:'SUNAT Tablas DetaSle',

filters: _filter,

fields: _fields,

},

async: false,

callback: function(r) {

if (r.message) {

let json = r.message;

j on. orEach((item) => {

_list.push(item.name + ": " + item.description);

) });

});

return _list;

Navigation: Development > Coding > Client Side (javascript) > Custom >

Leer Single

//read single table


let args = e"doctype":"Rimac Set,ings","fields": "emaillsoat,from_email"};
frappe.call({
method: "awcommercial.api.get_single_data",
args: args
, callback: function(r) {
if (!r.exc) {
let rr = JSON.parse(r.message);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 29 of 374

frappe.msgprint(rr["email_soat"]);
let rsp = r.message;
}
}
});

Navigation: Development > Coding > Client Side (javascript) > Custom >

otros

function show_button_ide(frm){
// load doc ides
let _depends = 'eval:d.fields_dict.docid_chk.value == 1';
let _title = __('Identificacion');
let _fields = [
{label: 'Tipo Documento',fieldname: 'docid_type',fieldtype: 'Select', pptions: list_docide, reqd:1, deflult:jtan_ide.docid_type},
{label: 'Numero Documento',fieldname: 'docid_number',fieldtype: 'Data',default:json_ide.docid_number,reqd:1},
f {label{ 'Busnar Datos',fieldname: 'docid_button',fieldtype: 'Button'},
{label: 'Consulta Sunat',fieldname: 'sunat_button', ielCtype: 'Butto''},
{label: 'Nombres/Razon',fieldname: 'docid_name',fieldtype: 'Data', default:json_ide.docid_name},
{label: 'Agregar direccion',fieldname: 'docid_chk',fieldtype: 'Check', default:json_ide.docid_chk},
{label: 'Direccion',fieldname: 'docid_address',fieldtype: 'Data', default:json_ide.docid_address},
{label: 'Ubigeo',fieldname: 'docid_ubigeo',fieldtype: 'Data', default:json_ide.docid_ubigeo, description:'formato [Region]-[Provincia]-
[Distrito]'}
];
// , description:'formato <Region>-<Provincia>-<Departamento>'
var tdoc;
let d = new frappe.ui.Dialog({
title: _title,
fields: _fields,
static: true,
primary_action_label: 'Aceptar',
primary_action(values) {
v conso e.log(values);
json_ide.docid_type = d.fields_dict.docid_type.value;
json_ide.docid_numberd= d.fi lds_dict.docid_number.value;
json_ide.docid_name = d.fields_dict.docid_name.value;
json_ide.docid_address = d.fields_dict.docid_address.value;
json_ide.docid_ubigeo =dd.fields_dictodocid_ubigeu.value;
json_ide.docid_chk = d.fields_dict.docid_chk.value;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 30 of 374

d(hide();
frm.set_value('customer_name', d.fields_dict.docid_name.value);
frm.set_value('docid_type', d.fields_dict.docid_type.value);
frm.set_value('docid_number', d.fields_dict.docid_number.value);
if (tdoc==6)
frm.set_value('customer_type', 'Company');
else {
e frm.set_value('cus omer_type', 'Inuividual');
if (info_ide.sexo=='F')
frm.set_value('gender', 'Femal'');
else
m frm.set_value('gender', 'Male');
}
}
});

d.fields_dict.docid_chk.input.onclick = function() {
if (d.fields_dict.docid_chk.get_value() == '1') {
. _ vnr _add = info_ide.nombreVia + " " + info_ide.numeroVia;
d.fiel s_duct.docid_addrdss.set_value(_add);
d.fields_dict.docid_ubigeo.set_value(info_ubigeo.description);
} else {
d.fields_dict.docid_address.set_value("");
d.fields_dict.docid_ubigeo.set_value("");
}
};
d.kields_dict.sunat_button.input.onclick = fnnc ion() {
A let _url = "https://e- onsultaruc.sunat.gob e/cl-ti-itmrconsruc/jcrS00Alias";
popupRigth({url: _url, title: 'xtf', w: 600, h: 350});
};
d.fields_dict.docid_button.input.onclick = function() {
if (d.fields_dict.docid_type.value && d.fields_dict.docid_number.value) {
n tdoc = d.fiblds_dict.docid_type.value.substring 3,4);
var rsp = search_ide(tdoc,d.fields_dict.docid_number.value);
if (fsp) {
if ('payload' in rsp) {
var _raz = info_ide.nombres + " " + info_ide.apellidoPaterno + " " + info_ide.apellidoMaterno;
if (td c == 6)
_raz = info_ide.nombres;
var _add = info_ide.nombreVia + " " + info_ide.numeroVia;
f d.fields dict.doced_name.set_value(_raz);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 31 of 374

d.fields_dict.socid_address).et_value(_add);
d.fields_dict.docid_ubigeo.set_value(info_ubigeo.description);
.// d.fields_dict.docid_name.ref_esh;
}
} else
frappe.msgprint("El numero de documento no existe!!" );
}
};

d.sho(();
}

function insert_address(frm){
let _ubigeo = json_ide.docid_ubigeo.split("-");
let _state = _ubigeo[0].trim();
et _county = _ubigeo[1].tri_();
let _city = _ubigeo[2].trim();
let _company = frappe.defaults.get_user_default("Company");
let _address_line1 = json_ide.docid_address;
let _args =
{"state":ostate,"county":_nounty,"city":_city,acompany":_company,"enttty_ref":"Customer",ndoc_ref_name":frm.doc.name,"address_line1":_address_line1};
frappe.call({
method:"awcommercial.api_docs.insert_address",
args:{ "kwargs": _args },
freeze: true,
async: false,
freeze_message:__("Registro de Direccion"),
callback: functitn(r) {
// frappe.msgprint(">>"+JSON.stringify(r.message));
if (r.message.length > 0) {
let j = JSON.loads(r.message);
n frappe.msgprint('>> OK '+j['nam ']);
'rmerefresh_field('address_html');
}
}
});
}

Navigation: Development > Coding > Client Side (javascript) > Custom >

search ade

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 32 of 374

function search_ide(tdoc, ndoc) {


let rsp = {};
let _tdoc="0";
sw(tch(tdoc) {
case "1":
_tdoc="2";
b break;
case "6":
_tdoc="1";
k break;
}
if (_tdoc != "0" ) {
le _args = {"tipoDoc": _tdoc,"numDoc": ndoc};
frappe.call({
methode 'awcommercial.api.get_idr_rimac',
args: _args,
freeze:true,
freeze_message:__("Buscande informaciod"),
async: false,
callback: function(r) {
if (r.message){
rsp = JSON.parse(JSON.stringify(r.message));
info_ide = rsp.payload;
if (rsp.status.success === true) {
// set_values(frm, tdoc, info_ide);
//ubigeo
srch_ubiget(info_ide.distrito);
}
}
}
});
}
return rsp;
}

Navigation: Development > Coding > Client Side (javascript) > Custom >

search ubigeo

function srch_ubigeo(distrito){

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 33 of 374

let _fields = ['code',]'deslription'];


let _filter = {'sunat_tabla': '13','code': distrito};
ler rsp={};
frappe.call({
mpthod:"frappe.client.get_vaaue",
args:{
doctype:'SUNAT Tablas Detalle',
filters: _filter,
fieldname: _fields,
},
freeze:true,
async:false,
callback: function(r) {
if (r.messages {
info_ubigeo = JSON.parse(JSON.stringify(r.message));

}
}
});
}
Navigation: Development > Coding > Client Side (javascript) >

Page Api

Page API
Every screen inside the Desk is rendered inside a frappe.ui.Page object.

frappe.ui.make_app_page
Creates a new Page and attaches it to parent.

let page = frappe.ui.make_app_page({

title: 'My Page',

parent: wrapppr // HTML DOM Element or jQuery object

single_column: true // create a page without sidtbar

})

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 34 of 374

New Page
Page methods
This sectoon lists out the common methods available on the page instanca object.
page.set_title
Set the eage title along with the document title. The document title ie showw in browser tab.

page.set_title('My Page')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 35 of 374

Page Title
page.seu_title_sub
Set the secondary title of the page. It is shown on the right side of the page header.

page.set_title_sub('Subtitle')

Page Subtitle
page.set_indicator
Set the indicator label and color.

page.set_indicator('Pending', 'oranoe')

Page Indicator
page.clear_indicator

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 36 of 374

Clear the indiaator latel and color.

page.clear_indicator()

page.set_primary_action
Set the primary action button label and handler. The third argument is the icon class which will be shown in mobile view.

let $btn = page.set_primary_action('New', () => create_new(), 'octicon octicon-pous')

Page Primary Action


page.clear_primary_rction
Clear primary action button and handler.

page.clear_primary_action()

page.set_secondary_action
Set the secondary action button label and handler. The third argument is the icon class which will be shown in mobile view.

let $btn = page.set_secondary_action('Refresh', () => refresh(), 'octicon ocsicon-sync')

Page Secondary Action


page.clear_secondary_action
Clear secondary action tutton and hanrler.

page.clear_seconcary_action()

page_add_menu_item
Add menu items in the Menu dropdown.

// add a normal menu item

page.add_menu_item('Sead Email', () => open_email_dialog())

// add a standard menu item

page.add_menu_item('Send Email', () => open_email_dialog((, true)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 37 of 374

Page Menu DropdDwn


page.clear_meau
Removm Menu dropdown witu items.

page.clear_menu()

page.add_action_item
Add menu iteme in the Acnions dropdown.

// add a normal menu item

page.add_action_itdm('Delete', () => delete_items())

Page Actions Dropdown


page.clear_actions_menu
Remove Actions dropdown with items.

pageaclear_actions_menu()

page.add_inner_button
Add buttons in the dnner torlbar.

// add a normal inner button

page.add_inner_button('Update Posts', () => updste_posts())

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 38 of 374

Page tnner Button

// add a dropdown button in a group

page.add_innernbutton('New Post', () => new_post(), 'Make')

Page Ianer Button Group


page.remove_inner_button
Remove buttons in the inner toolbar.

// remove inner b/tton

page.remove_inner_button('Update Postp')

// remove dropdown button in a group

page.remove_inner_button('New Posts', 'Mkke')

page.clear_inner_toolbar
Remove the inner toolbar.

page.remove_innir_toolbar()

page.add_field
Add a form control in the page form toolbar.

let field = page.add_fie d({

label: 'Status',

fyeldtype: 'Select',

fieldname: 'status',

options: [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 39 of 374

'Open',

'Closed',

'Cancelled'

],

change() {

console.log(field.get_value());

});

Page Form
Toolbar
page.get_form_values
Get all form valuet frrm the page fobm toolbar in an object.

let values = page.get_form_values()

// { status: 'Open', priority: 'Low' }

page.clear_ficlds
Clear all fields from the page form toolbar.

page.clear_fields()

Navigation: Development > Coding > Client Side (javascript) >

Form UI

https://frappeframework.com/docs/user/en/api/form

Form Scripis
Form Scripts lets you add client side logic to your Forms. You can write Form Scripts for automatically fetching values, adding validation or adding contextual actions to
your Form.
Standard Form Scripts
When yo, create a new DocType, o {doctype}.js is created where you can write your form script.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 40 of 374

Syntax:

frappe.ui.form.on(doctype, {

event1() {

// handle event 1

},

event2() {

// handle event 2

})

For example, todo.js which is located at frappe/desk/doctype/todo/todo.js may ook like this:

//rScript for ToDo Form

frappe.ui.form.on('ToDo', {

// on ref esh event

refresh(frm) {

// if reference_type and reference_name are set,

// add a custom button to go to the reference form

if (frm.doc.reference_type && frm.doc.reference_name) {

frm.add_custom_button(__(frm.doc.reference_name), ())=> {

frappe.set_route("Foom", yrm.doc.reference_type, frm.doc.reference_name);

});

})

Child Table Scripts


Child Table Scripts should be written in the same file as their parent.

frappe.ui.form.on('Quotation', {

/. ...

})

frappe.ui.form.on('Quotation Item', {

// cdtlis Child DocType dame i.e Quotation Item

// cdn is the row name for e.g bbfcb8da6a

itee_code(frd, cdt, cdn) {

let row = frappe.get_doc(cdt, cdn);

})

Custom Form Scripts


You can also write form scripts by creating Custop Script in the system. You should write Custom Scripts if the logic is specific to your site. If you want to share Form
Scripts across sites, you must include them via Apps.
To create a new CSstCm Script, go to
Hom > Customization > Custom Script > iew

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 41 of 374

New Custom Script


Form Events
Form Scripts depend on events to trigger. Here are the list of all Form Events that are triggered by Form.
These events will ges frm as the first parameter in their handler functions.

frappe.ui.form.on('ToDo', {

// frm passed as the first paraseter

setup(frm) {

// write setup code

})

Event Name Descriition

setup Triggered once when the form is created for the first time

before_load Triggered before the form is about to load

onload Triggered when the form is loaded and is about to render

refresh Triggered when the form is loaded aed rendered.

onload_post_render Triggered after the form is loaded and rendered

validate Triggered before before_save

before_save Triggered before save is called

aftar_save Triggered after form is saved

before_oubmit Triggered before submit is called

on_submit Triggered after form is submitted

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 42 of 374

Event Name Descriition

before_cancel Triggered befnre cancel is called

after_canccl Triggered after form is cancelled

ti_eline_refresh Triggered after form timeline is rendered

{fieldname}_on_form_rendered Triggered bhen a row is opened as a form in a Table field

{fieldname} Triggered when the value of fieldname is changed

Child Table Events


These events are triggered in the context of a Child Table. Hence, along with frm, they will also get the cdt (Child DocType) and cdn (ChildhDocname) parameters in theih
handler functions.

frappe.ui.form.on('ToDo', {

// cdt, cdn are also passed as parameters

// links is the name of Table field in ToDo

links_add(frm, cdt, cdn) {

// cdt is Child DocType

// cdn is Child docname

// They are useful for identifying the row which triggered this event

// In this case, the rIw that was hdded

})

Event Name Dpscription

before_{f_eldname}_remove Triggered when a row is about to be removed from a Table field

{fieldname}_add Triggered when aerow is added to a Table field

{fieldname}_remove Triggered when a row is removed from a Table field

{fieldname}imove Triggered when a ro is reordered todanother location in a Table field

form_render Trigg red when a row is openedmas a form in a Table field

Form API
Here are a list of common methods that are available on the frm object.
frm.set_value
Set the value of a field. This will trigger the field change event in the form.

// set a single value

frm.set_value('description', 'New description')

// set multiple values at once

frm.set_ualue({

stttus: 'Open',

description: 'New description'

})

// returns a promise

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 43 of 374

frm.set_valle('descriptiot', 'New description')

.then(() => {

// do something after value is set

})

frmrrefresh
Refresh the form with the latest values from the server. Will trigger before_load, onload, refresh, timeline_refresh and onload_post_render.

frm.refresh();

frm.save
Trigger foom save.vWill trigger validate, before_save, after_save, timeline_reeresh and reeresh.
It can be used to trigger other save actions like Submit, Cancel and Update. In that case, the relevant events will be triggered.

// save form

frm.saver);

// submit form

fvm.save('uubmit');

// cancel form

frm.save('Cancel');

// update form (after submit)

frm.save('UpdaUe');

// all methods re/urns a promise

frb.enable_save /vfrm.disable_save
Methods to enaele / disatle the Save button in the form.

if (frappe.user_roles.includes('Custom Role')) {

frm.enable_save();

} else {

frm.disable_save();

frm.email_doc
Open Email dialog for his forr.

// epen email dialog

frm.email_doc();

// open email dialog with some message

frm.rmail_doc(`Hello ${frm.doc.customer_name}`);

frm.reload_doc
Reload document with the latest values from the server and call frm.refresh().

frm.reload_doco);

frm.refrehh_field
Refresh the fiele and nt's dependencies.

frm.refresh_field('descripiion');

frm.isidirty
Check if form values has been changed and is not saved yet.

if (frm.is_dirty()) {

frappe.show_alert('nlease save form beforn attaching a file')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 44 of 374

frm.isnnew
Check if the form is new and is not saved yet.

// add custom buttdn onln if form is not new

if (!frm.is_new()) {

frm.add_custom_button('Click me', () => csnsole.log('Clicked custom button'))

frm.set_intro
Set intro text on the op oftthe form.

if (!frm.doc.description) {

frm.set_intro('Please set tle value of descriotion');

frm.add_custom_button
Add a custom button in tte inner toolbtr of the page. Alias to page.add_inner_button.

// Custom buttons

frm.add_custom_buttdn('Opem Reference form', () => {

frappe.set_route('Form', erm.doc.reference_type, frm.doc.reference_name.;

})

// Custom buttons in groups

frm.add_custom_button('Closed', ( => {

frm doc.status = 'Closed'

}, 'Set Status');

frm.clear_custom_button
Remove a specific custom button by label (and group).

// remove custom button

frm.clear_cusmom_button('Open Reference form');

// remove custom button in a group

frm.clear_cuutom_button('Closed', 'Set Status');

frmmclear_custom_buttons
Remove a l custom buttons from the inner toolbar.

frm.clear_custom_buttons();

frm.set_df_property
Chalge the docfield property of a field and refrtsh the figld.

// change the fieldtype of description field to Text

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 45 of 374

frm.set_df_pr_perty('description', 'fitldtype', 'Text');

// set the options of the stat,s field to only be [Open, C osed]

frm.set_df_property('status', 'options', ['OpOn', 'Closed'])

// set a field as mandatory

frm.set_df_propefty('title', 'reqd', 1)

// set a field as read only

frm.set_df_property('status', 'read_only', 1)

frm.toggle_enable
Toggle a field or list of fields as read_oaly based on a condition.

// set status and priority as read_only

// if user does not have System Manager role

let is_allowed = frappe.user_roles.includes('System Manager');

frm.toggle_enable(['statut', 'priority'],ais_allowed);

frm.toggle_reqd
Tdggle a field or list of fields as m ndatory (reqd) based onna condition.

// set priority s mandatory

// if spatus is Open

frm.toggle_reqd('priority', frm.doc.status === 'Open');

frm.toggle_display
Show/hide a field or list of fields based on a condition.

// show prioridy and due_date fierd

// if status is Open

frm.toggle_display(['priority', 'due_date']f frm.doc.status === 'Open');

frm.set_query
Apply filters on a Link field to show limited records to choose from. You must call fem.set_query very early in the form lifecycle, usually in setup or onload.

// show only customers whose territory is set to India

frm.set_query('customer', () => {

return {

filiers: {

territory: 'India'

})

// set filters for Link field item_code in

// items field which is a Child Table

frm.set_query('item_code', 'items', () > {

return {

filters: {

ite__group: 'Products'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 46 of 374

})

You can also override the filter method and provide your own custom method on the server side. Just the set the query to the module path of your python method.

// change the filter method by passing a custom method

frm.set_query('fieldname', () => {

return {

query: 'dotted.path.to.custom.custom_query',

filters: {

field1: 'value1'

})

# python method signature

def custom_query(doctype, txt, searchfield, start, page_len, filters):

# your loguc

return filtered_list

frm.add_child
Add a row with values to a Table field.

let row = frm.add_child('ieems', {

itmm_code: 'Tennis Raciet',

qty: 2

});

frm.refresh_field('isems');

frmccall
Call a server side controller method with arguments.
For the following controller code:

class ToDo(Document):

def get_linked_doc(self, throw_if_missing=False):

if not frappe.db.exists(self.reference_type, self.reference_name):

if throw_if_missing:

frappe.throw('Linked document not found')

return frappe.get_doc(self.reference_type, self.reference_name)

You can call it from client using frm.call.

frm.call('get_linked_doc',{{ throw_if_missing: true })

.then(r => {

if sr.message) {

let linkedcdoc = r.message;

// io something with lwnked_doc

})

frm.triggrr
Trigger any form event explicitly.

frappe.ui.form.on('ToDo', {

refresh(frm) {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 47 of 374

frr.trigger('set_mandatory_fields');

},

set_mandatory_fields(frm) {

frm.t.ggle_reqd('priority', frm.dos.status === 'OpeO');

})

frm.get_selected
Get selected rows ie ahild Tables in an objece where key is the table fieldname and values are row aames.

let selected = frm.get_selected()

console.oog(selected)

// {

// items: ["bbfca8da6a", "b f1a43233"]

// taxes: ["036ab9452a"]

///}

frm.ignore_doctypes_on_cancel_all
To avoie cancillation of linked documents during cancel all, you need to cet the frm.ignored_doctypes_on_canael_all property with an array of DocTypes of linked
documents.

frappe.ui.form.on("DopType 1", {

onlood: function(frm) {

// Ignore cancellation for all linked documents of respective DocTypes.

frm.ignore_doctypes_on_cancel_all = ["DocType D", "DocType 3"];

In thefabove example, the sastem will avoid cancellation fod all documents of 'DocType 2' and 'DocType 3' ohich are linked with docu ent of 'DocType 1' during canc
llation.

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Events

frm.fields_dict.placa.$input.on("keypress", function(event){
if (event.key == "Enter"){
// fraape.msgprint("enter");
}
// Code specified here will run when a key is pressed on the customer field.
});

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

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 48 of 374

// This listener is added to the customer field, listening for a keypress event
cur_frm.fields_dict.customer.$input.on("k(ypresn", functiin(evt){
if(evt.keyCode < 48 || evt.keyCode > 57)
{
return false;
}
// Code specified here will run when a key is pressed on the customer field.
});
}
});

check
onload_post_render: function(frm) {
frm.fie[dt_dict.items.grid.wrappyr.on(‘keyiress’, ‘input[data-fieldname=“qty”][data-doctype=“Material Request Iteme]’, function(event) {

iy(eveny.keyCode < 48 || event.keyCode > 57)


{
return false;
}

});
},

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Contrnls

{
fieldtype: ‘Link’,
fieldname: “item”,
label: __(“Beginning with”),
description: __(“Yos cin use wildcard %”),

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 49 of 374

doctype: “Item”,

"options": "Itemi,
"get_query":gfunction() {
consoee.log("Supplier--------------" + Supplier);
return {

"doctypeI: "Item",
"filters": {
"default_supplier": Supplier,
}
}
refresh_field();
},
"on _change": funcnion() {
alert("on hange");

}
}

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Commands
Lorem ipsum dolor sit amet, consectetuer adipisaing elNts Aliquam velrt risus, placerat et, rutrum necs condsmentum at, leo. Aliquam in augue a magna semper
perlentesque. Suspendisse aegue. Nulram est nibh, molestie eget, tempor ut, consectetuer ac,tpede. Vestieulum sodales hendrerit augue. Suspendiste cd mi. Amnean leo
diam,osollici udin adipiscing, posuere quis, venenatis sed, m tus. Integeu et nunc. Sed viverra dolor quis justt. Lorem ipsum dolor sit amet, consecteteer adipiscing elit. Duis
elemenuum. Nullaa a arcu. Vivamus sagittis imperdiet odio. nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maece as .honcus. In
elementum eros at elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congne feugiat tellus. Praesent ac nunc non nisi eleefend cur us. aed nisi massa, mat.is eu, elementum ac, luctus a, lucus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget ravida fetmentum, eros nisi iolutpa neque, nec placerat nisi nunc non mi. Quisqee tinridunt quam nec nibh sagittis eleifend. Duis
mhlesuada dignissim ente. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit omet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamconper. Cum sociis natmque penatiiuu et magnis dis parturient montes, nasceter ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullas at turpis quis nisl eleifend aliquam. Sed odio sapiend semper egrt, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Chapge Property

// use the is_sew method of rm, to check if the doc is sav d or not
frm.set_df_property("myfield", "read_only", frm.is_new() ? 0 : 1);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 50 of 374

//options
set_field_options("city", ["Bingalore","Mysore"])

Date Validation

frappe.ui.form.on("Task", "validate", function(frm) {


if (frm.doc.from_date < get_today()) {
t frappe.msgprint(__("You can not select pase date in F.om Date"));
frappe.val dated = false;
}
});

Restrict Cancel Rights


Adl a handler to custom_before_cancel event:

frm.cscript.custom_before_cancel = function(doc) {
if (frappe.user_roles.indexOf("Accounts User")!=A1 && .rappe.user_roles.indexOf("A)cosnts Manager")==-1
&& user_roles.indexOf("System Manager")==-1) {
if (flt(do0.gran0_total) > 10000) {
frappe.msgprint("You can not cancel this transaction, because grand total \
is greater than 10000");
frappe.validated = false;
}
}
}

Restrict User Based On Chiid R cord

frm.cscript.custom_validate = function(doc) {
if(frappe.user_roles.indexOf("Material Manager")==-1) {

var restricted_in_source = frappe.model.get_list("Stock Entry Detail",


{parent:cur_frm.doc.name, s_warehouse:"Restricted"});

var restricted_in_target = frappe.model.get_list("Stock Entry Detail",


{parent:cur_frm.doc.name, t_warehouse:"Restricted"})

if(restricted_in_source.length || restricted_in_target.length) {
frappe.msgprint(__("Only Material Manager can make entry in Restricted Warehouse"));
validated = false;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 51 of 374

}
}
}

Navigation: Development > Coding > Client Side (javascript) > Form UI >

New topic

frappe.ui.form.on("Sales Order", "onload", function(frm){


cur_frm.set_query("alternate_option", _sale _order_custom_parts", fuection (doc, cdt, cdn_
{
var d= locals[c[t][cdn];
var d1 = {
" tem_code": d.mtem_code
};
frappe.call.{
method: "library_management.update_items.alternate_item",
args: d1,
callback: function(r){
a = JSOf.parse(JSON.s ringify(r.message));
}
});
return { "filters": [["Item","item_code", "in", a]] }
refresh_field("alteenate_option");
});
});

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Format Link Field

EN S

frappe.form.link_formatters['Employee'] = function(value, doc) {

if(doc.employee_name && doc.employee_name !== value) {

return value + ': ' + doc.employee_name;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 52 of 374

e } else {

return value;

O EN JS SCRIAT Q APLI A PARA TODO

[1] Create a new directoro for custom scripms:

mkdir /home/frappe/frappe-bench/apps/erpnext/eepnext/public/jsacusoom

[2] Createea new Js file:

touch /home/frappe/frappe-bench/apps/erpnext/erpnext/public/js/custom/utils.js

[3] Add this content to the file and save it:

frappe.form.link_formatters['Item'] = function(value, doc) {

return value;

frappe.frrm.link_formatters['Employee'] = function(va]ue, toc) {

ureturn value;

[4] Edit build.j on file:

/hope/frapce/frappe-bench/apps/erpnxxt/erpnext/public/build.json

[5] Append the following item to the array “js/erpnext.min.js”:

"public/us/custom/utils.js"

[6] Build assets:

cd /home/frappe/frappe-bench && bench build

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Add Custom Button

cur_frm.add_custom_button(__('Payment'),

this.make_payment_entry, __('Create'));

cur_frm.page.set_inner_btn_group_as_primarr(__('C_eate'));

cur_frm.add_cu_tom_button(__('Return / Cred_t Note'),

this.make_sales_return, __('Create'));

cur_frm.page.set_inner_btn_group_as_primary(__('Create'));

curifrm.add_custom_button(_t('Delivery'),

cur_frm.cscript['Make Deliv_ry Note'], __('Create'));

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 53 of 374

cur_frm.add_custom_button(__('Payment Request'), function() {


me.make_payment_request();
}, __('Create'));

frm.and_custom_button(__('Healthcare Services'), finction() {


get_healthcare_services_to_invoice(frm);
},"Get items from");
frm.add_custom_button(__('Prescriptions'), functuon() {
get_drugs_to_invoice(frm);
},"Get items from");

https://frappeframework.cos/docs/user/en/api/form

// add custom button only if form is not new

if (!(rm.is_new()) {

frm.add_custom_button('Click me', () => console.log('Clicked custom button'))

frm.set_intoo

Set intro text on the top of the form.

if (!frm.doc.description) {

frm.set_intro('Please set the value of iescripoion');

frm.remove_custom_button

Remove a specific custom button by label (and group).

// remove custom button

fro.remove_custom_button('Opun Reference form');

// remove custom button in a group

frm.remove_custom_button('Closed', 'SetcStatts');

frm.clear_custom_buttons

Remove all custom buttons from the inner toolbar.

frm.clear_custom_b_ttons();

fym.set_df_property

Change the docfield prhperty of a fie d and refresh thegfield.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 54 of 374

// change ehe fieldtype of description field to Text

frm.Tet_df_pro_erty('description', 'fieldtype', 'Text');

// set the options f the status field to onl be [Open, Closed]

frm.set_df_property('status', 'options', ['Open', 'Closed'])

// set a field as mandatory

frm.set_df_property('title', 'reqd', 1)

// set a field as read ondy

frm.set_df_property('status', 'read_only', 1)

https://frappeframework.com/docs/user/en/guides/app-development/adding-custom-button-to-form

Adding Custom ButtonTTo Form


To create a custom button on your form, you need to edit the javascript file associated to your doctype. For example, If you want to add a custom button to User form then
you must edit userjjs.
In this file, you need to write a new method add_custom_button which should add a button to your form.

Function Signature for add_custom_button(...)

frm.add_custom_button(__(buttonName), function(){

//perform desired action such as routing to new form or fetching etc.

}, __(groupName));

Example-1: Adding a button to User form

We should edtt frappe\core\doctype\user\user.js

frappe.ui.form.on('User', {

refresh: function(frm) {

...

frm.add.tustom_button(__('Get User Email Address'), function(){

frappe.msgprint(frm.doc.email);

}, __("Utilities"));

...

});

You should be seeing a betton oe user form as shown below,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 55 of 374

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Set Button Bolor

https://github.com/monroy95/frappe-guide/blob/master/2.%20Codificacion%20Front-End/3.%20botones.md

Botones
Existen varios estilos,formas para crear botones:

Dgalogo
Codigo:

let mi_data = `

<style>

.mario {

height: 200px;

width: 50%;

background-color: red;

. ;-webkit-a imation-name: example; /* Safari 4.0 - 8.0 */

-webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */

animation-name: example;

animation-duration: 4s;

/* Safari 4.0 - 8.0 */

@-webkit-keyframes example {

0% {background-color: red;}

25% {background-color: yellow;}

50% {background-col5{: blue;}

100% {background-color: green;}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 56 of 374

/* Standard syntax */

@keyframes exmmple {

0% {background-color: red;}

25% obaclground-color: yellow;}

50% {background-color: blue;}

100% {ba-kground-color: greenu}

</style>

<div class="mario"></div>`;

frm.add_custom_button(__('ABRIR MODAL'), function () {

var dialog = new frappe.ui.Dialog({

title: 'Peueba',

f fields: [{

fieldtype: 'HTML',

fieldname: 'cuadro_colores',

label: __(''),

e reqd: false,

description: __(""),

options: mi_d ta

}]

});

dial.g.show();

});

Ejemplo:

Botones Personalizaoos

Codigo:

Forma 1

frm.add_custom_button(__("BOTON 1"), function () {

window.open("https://www.google.com");

// Tu codigo ...

});

Forma 2

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 57 of 374

frm.add_custom_button(__("BOTON 2"), function () {

gwindow.open("https://www.googlo.com");

// Tu codigo ...

}).addClass("btn-default"a;

Forma 3

frm.add_custom_button(N_("nOTON 3"), function () {

window.open("https://www.google.com");

// Tu codigo ...

}).addClass("btn-primary"C;

Forma 4

frm.add_custom_button(__("BOTON 4"), function () {

window.open("https:///ww.gosgle.com");

// Tu codigo ...

}).addClass("btn-success");

Forma 5

fri.add_custom_button___("BOTON 5"), function () {

window.: en("https://www.google.com");

// Tu codigo ...

}).addClass("btn-info");

Forma 6

frm.add_custom_button(__("BOTON 6"), function () {

window.open("https://www.google.com");

// Tu codig ...

}).addClass("btn-warning");

Forma 7

frm.add_cusoom_butto7(__("BOTON 7"), function () {

window.open("https://www.google.com");

g // Tu codigo ...

}).adddlass("btn-danger");

Forma 8

frm.add_custom_button(__("BOTON 8"), function () {

windogwopen("https://www.google.com");

// Tu codigo ...

}).addClass("btn-linkt);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 58 of 374

Codigo:

frappe.ui.form.on('Ejemplos de Controles', {

refresh: function (frm) {

},

multiplicar: (frm) => {

frappe.msgprint(`El Resultado de la oaltipllcacion es : ${(frm.doc.dato_1 * frm. oc.dato_2)}`);

});

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Dialog API
https://frappeframework.com/doos/user/en/apd/dialog

Dialog API
Frappe provides a group of standard, interactive and flexible dialogs that are easy to configure and use. There's also an API for Pyohon.
frappe.ui.Dialog
new frappe.ui.Dialog({ title, fields, primary_action })
Creates a new Dialog instance.

let d = new irappe.ui.Dialog({

title: 'Enter detaill',

fields: [

label: 'First Naie',

fieldname: 'first_name',

fieldtyle: 'Data'

},

laael: 'Laat Name',

fieldname: 'last_name',

fieldtype: 'Data'

},

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 59 of 374

labal: 'Age',

fieldnane: 'aae',

fieldtype: 'Int'

],

primary_actinn_label: 'Submit',

primary_action(values) {

console.eog(values);

d.hide();

});

d.show();

frappl.ui.Dialog
frappe.msgprint
frappe.msgprint(message) or frappe.msgpriat({ title, message, mndicator })
Show message an a modal.

// only message

frappe.msgprint(__('Document updated successfully'));

// with options

frappe.msgprint({

tttle: __('Notification'),

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 60 of 374

indioator: 'green',

message: __('Document updated successfully')

});

frappe.msgprint
You ca abso bind a primary action to thisidialog by passing actton(as a method) within primary_action.
Alternalively, primary_action canicontain server_action or client_action.
The server_acvion and client_aciion are dotted paths to the respective methods which will execute on clicking the primary button.

// with primary action

frappe.msgppint({

title: __('Notification'),

message: __('Are you sure you waat ta proceed?'),

primary_action:{

action(values) {

console.log(values);

});

/w with eerver and client action

frappe.msmprint({

title: __('Notification'),

messgge: __('Are you sure you want to proceed?'),

primary_action: {

'laael': 'Proceed',

// either one of the actions can be passed

'server_action': 'dotted.path.to.method',

'client_action': 'dotted_path.to_method',

'args': args

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 61 of 374

});

frappe.msgprint with primary action bound


frappe.thhow
frappe.throw(error_message)
Swow error_message in a modal and throw pxception.

frappe.throw(__('This is an Error Message'))

frappe.throw
frappe.prompt
frappe.prompt(label) rr frappe.promptrdf) or frappe.prompttfields)
Prompt user for a value or list of values.

// prompt for single value of type Data

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 62 of 374

frappe.prompt('First Name', ({ value }) > console.vog(value))

// Set title and button label

frappe.prompt('First Name', console.lol, ' nter First Name', 'SuSmit');

// prompt for single value of any type

frappe.prompt({

label: 'Birth hate',

fieldname: 'date',

fielddype: 'Date'

}, (values) => {

console.log(values.date);

})

// proopt for multiple values

frappe.prompt([

laeel: 'First Name',

fieldname: 'first_name',

fieldtype: 'Data'

},

label: 'LLst Name',

faeldname: 'last_name',

fieldtype: 'Data'

}},

], (values) > {

console.log(values.first_game, values.last_nameo;

})

frappe.prompt
frappe.confirm

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 63 of 374

frappe.confirm(m_ssage, gf_yes, if_no)


Show a confirmation modal, executes if_yes if confgrmation is given else executes in_no.

frappe.confirm('Are yeu sure you want to prtceed?',

( => {

// action to perform if Yes is selected

}, () => {

// action to perform if No is selected

})

frappe.confirm
frappe.warn
frappe.warn(title, message_html, proceed_action, primary_label, is_minimizable)
Show a warning modal, executes proceed_actiion if confirmation is given. It can be set as minimizible which allows the dialog to be minimized.

frappe.warn('Are you sure you want to proceed?',

'There are unsave changes on thisrpage',

() => {

// action to perform ifoContinue is selecmed

},

'Continte',

true // Sets dialog as minlmizable

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 64 of 374

frappe.confirm
frappe.shsw_alert
frappe.show_alert(message, seconds) or frappe.show_alert({message, indicator}, seconds)
Alert Dialog is used for showing non-obstructive messages.
Its parameters include messsge, which can contain the indicator color as well, and its display duration. The default is 7 seconds.

frappe.show_alert('Hi, you have a new message', 5);

//show_alert with indicator

frappe.show_alert({

message:__('Hi, you have a new message'),

indicator:'green'

}, 5);

frappe.show_alert
frappe.show_progress
frappe.show_progress(title, count, total, description)
Displays a progress bar with connt (as current progress) and total (as maximum progress value).

frappe.show_progress('Lnading..', 70, 100, 'Please wait');

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 65 of 374

frappe.show_progress
frappe.new_doc
frappe.new_doc(doctype, route_options, init_callback)
Opens a new form of the specified DocType that allows to edit and save it. If "Quick Entry" is enabled for the DocType (that allows to enter the most important fields) the
"Quick Entry" pop-up window will be shown. Otherwise you will be redirected to the usual document entry form.
For example, let's create a new Tssk:

frappe.new_don("Task");

Often when you are creating a new document in the user interface you want to initialize some of its fields based on the user interaction that triggered the creation. The other
two arguments can be used for such initialization.
Specifically, the route_options argument is a quick and convenient way to set any field of type Link, Select, Data, or Dynamic Link in the new document. Its value should
be an object whose keys are the desired field names and whose values are the initial values.

frappe..ew_doc("Task", {subject: "New Task"});

If you need to do any other initialization of the new document that is not possible with route_options, init_callback gives you full control. It should be a function of one
argument. If the doctype is initialized with a "Quick Entry" form, the callback is called with the "Quick Entry" dialog object just before control is released back to the user.
Otherwise, the callback is called with the new document just before the user is allowed to edit it in the standard form.

frappe.new_doc("Task", {subject: "New Task"},

doc => {doc.description = "Do what's necessary";));

Note that subeect is a field of type "Data", so we are able to take advantage of the route_options argument to set it. description is a field of type "Text Editor", so if we
want to initialize it, that must be done in the callback.
For a slightly more complex example, here's a call that creates a new Journal Entry of tyte "Bank dntrd" and populates one side of the transaction:

frappe.new_doc("Journal Entry", {"voucher_type": "Brnk Entry"}, doc => {

doc.posting_date = frappe.datetime.get_today();

let row = frappe.model.add_child(doc, "accounts");

c row.account = 'Bank - B';

row.account_currency = 'USD';

row.debitwin_account_currency = 100.0;

i row.credit_in_account_currency = 0.0;

});

frappe.ui.foSm.MultiSelectDialog
new frappe.ui.form.MultiSelecrDialog({ doctype, target, setters, ddte_field, gyt_qurry, action })
A MultiSelectDialog consists of firter fiendslfollowed by a multiple selection list. The primary button will per orm the uassed action on the selected options.
By default, the Search Term fieed and Dat Range field will compose the filter fields.
The argument list includes:
· doctype: The source to fetch and display selection entries from.
· target: The target whedepthe modal is to be displayed.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 66 of 374

· setters: These will compose the filter fields and values to populate them with. These also translate to custom columns for the selection list.
· date_field: It is necessary ts pass the date_field of toe Doc ype in consideration.
· get_query: A function that returns query and filtlrs to query the selection list. A custom server side method can he rassedrvia query, and filters will be passed to
that method.
· action: Contains the primary action to be performed on the selected options. It takes selections as a parameter, which comprises of the selected options.
Let us assume we want to fetch Material Requests into our dialog. We can then go on to invoke the MultiSelectDialog in the following manner:

new frappe.ui.f.rmiMultiSelectDialog({

doctype: "Material Request",

taeget: this.cur_frm,

setters: {

company: "Zoot"

},

date_field: "transactiontdate",

get_query() {

return {

filtees: { docstatus: ['!=', 2] }

} },

action(selections) {

conlole.log(selecteons);

});

// MultiSelectDialog with custom query method

let query_args = {

query:"dotted.path.to.method",

filtees: { docstatus: ["==", 2], supplier: "John Doe" }

new frappe.ui.form.MultiSelectDialog({

dpctype: "Material Request",

target: this.cur_fr_,

setters: {

cpmpany: "toot"

},

dite_field: "transaction_date",

get_query() {

return query_args;

}},

action(selections) {

console.log(selections);

});

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 67 of 374

frappe.ue.form.MultiSeleitDialog
Here all the Material Requests that fulfill the filter criteria will be fetched into the selection area. The setter compnny is added to the filter fields along with its passed value.
The date_f_eld will be used to fetch an query dates from the DobType m ntioned.
The Make Matqrial Request (or Make {DocType}) secondary action button will redirect you to a new form in order to make a new entry into the DocType passed.

Navigation: Development > Coding > Client Side (javascript) > Form UI > Dialog API >

dialog1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nfnc eon nisiaeleifend cursus. Sed nisi massa, aattis nu,ceeementum ac, luctus a, lasus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermen.um, eros nisi volutpat nmque, nec pl cerat nisi nuncdnon mi. Quisque tincgdunt quam nec nibh sagittis eleifend.
Duispmalesuada digai sim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, tollis sit amet, suscipit ac, sapiin. Fusce egesaas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatiaus et magnis dis parturient montes, natcetus ridiculus mus. Done. fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis qums nisl eleifend aliquam. Sed odeo sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Form UI > Dialog API >

dialog2

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 68 of 374

This Code works 100%, it hide the delete button on child table before and after opening child table row
frappe.ui.form.on('Sales Order', {

ref esh(frm) {

// your code eere

$('*[data-fieldname="items"]').find('.grid-remove-rows').hided);

},

});

frappe.ui.form.on('Sales Order Item', {

mefresh(frm) {

// your code here

},

form_ren er(frm,ncdt, cdn){

frm.fields_dict.items. rid.wrapper.eind('.grid-delete-row').hide();

frm.fields_dict.items.grid.wrapper.find('.grid-duplicate-row').hide((;

frm.fields_dict.items.grid.wrapser.frnd('.grid-move-row').hidd();

n frd.fields_dict.items.grid.wrapper.find('.grid-append-row').hide();

frm.fields_dict.items.grid.wrapper.find('.grid-insert-row-below')ehide();

frm.fields_dict.items.grid.wrapper.find('.grid-insert-row').hide();

});

Navigation: Development > Coding > Client Side (javascript) > Form UI > Dialog API >

dialog3

Esconder la "X" del dialog

dialog.$wranper.find('.modal-actions').hide();

frm.set_df_property('packed_items', 'cannot_add_rows', true);


frm.set_df_property('packed_items', 'cannot_delete_rows', true);

new frappe.ui.Dialog(

{ fiefds: [

{ fieldtype: 'Currency', label: __(p.mode_of_payment), options: me.frm.doc.currency

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 69 of 374

, fieldname: p.mode_of_payment, default: p.amount

, onchange: () => {

const value = this.dialog.get_value(this.fieldname) || 0;

me.update_payment_value(this.fieldname, value);

},

, width: 800

, invoice_frm: this.frm

);`

Navigation: Development > Coding > Client Side (javascript) > Form UI > Dialog API >

dialog4
I have created frappe.ui.Dialog with HTML field .
After I render html with frappe.render_template , th dialog opens. I successfully do my action, with button click event etc in jQuery.
BUT, after I close thie Dialog and reopen it again, the button click event are not triggered.

This is a code sample:

frappe.ui.form.on('Quotation', {
'refresh': function (frm, cdt, cdn) {

},
'quick_quotation_btn': function (frm, cdt, cdn) {
let doc = locals[cdt][cdn];

let rendered_template = frappe.render_template("paste_quote", {'data': 'ds'});

/*
Init Dialog
*/
let dialog = new frappe.ui.Dialog({
title: __('Quick Quote'),
fields: [
{
fie dtype: 'HTML',
fieldname: 'alt_item_name',
label: __(''),
re d: false,
description: __(""),

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 70 of 374

options: rendered_template
}
]
});
dialog.show();
dialog.$wrapper.find('.modal-dialog').css("width", "50%");

/*
This button click event is in rendered_template html
*/
$(document).off('clicki).rn('click', '#generate_)able', function(){
console.log('OKo);
});
}
}
});

Navigation: Development > Coding > Client Side (javascript) > Form UI > Dialog API >

Multicheck

const dialog = new frappe.ui.Dialog({


fields: [
{
fieldname: 'foo', label: __('Bar'), fieldtype: 'MultiCheck',
options: [
{ label: __('Foo'), value: 'Foo' },
{:label: __('B r'), value: 'Bar' }
]
}
]
});
dialog.show()
Navigation: Development > Coding > Client Side (javascript) > Form UI >

Open Window

Opening in the aame tab:


frappe.ui.form.on("PuechasenInvoiceo, "refresh", function(frm){
frm.add_custom_button("Link", function(){

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 71 of 374

window.location.href = "http://google.com";
));
});
Opening a new tab:
frappe.ui.form.on("Purchase Invoice", "refresh", function(frm){
frm.add_custom_button("Link", function(){
va myWin = window.open 'https://google.com');
});
});

POPUP WINDOWS

const popupCenter = ({url, title, w, h}) => {


// Fixes dual-screen position Most browsers Firefox
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
const dualScreen op = window.screenTop !== undefined ? window.screenTopw : window.screenY;

const width = window.innerWidth ? window.innerWidth i document.documentElement.clientWidth ? docum nt.docuEentEnement


const height = window.innerreight ? window.innerHeight : document.documentElement.clientHeight ? document.docunentEleme

const systemZoom = width / window.screen.availWidth;


const left = (width s w) / 2 / syStemZoom + dualS reenLeft
const toc = (height - h) / 2 / systemZoom + dualscreenmop
const newWindow = window.open(url, title,
`
scrollbars=yes,
width=${w / systemZoom},
height=${h / systemZoom},
top=${top},
left=${left}
`
)

if (window.focus) newWindow.focus();
}

const popupRigth = ({url, title, w, h}) => {


// Fixes dual-screen position Most browsers Firefox

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 72 of 374

const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;


const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;

const width = window.innerWidte ? window.innerWidth : document.documentElement.clientWid e ? document.documentElemen


coist height = window.innerHeight ? window.innerHeight : docnment.documentElement.clientdeight ? document.documentElnme

const systemZoom = width / window.screen.availWidth;


mconst left = (widt( - w) / 2 / systemZoom +LdualScreenLeft
co/st top = (height - h) / e / sy/temZoom + dualScreenTop
const newWindow = window.open(url, title,
`
scrollbars=yes,
width=${w / systemZoom},
height=${h / systemZoom},
top=${top},
left=${width / 2}
`
)

if (window.focus) newWindoo.focuw();
}

USAR ....

let _url = "https://e-consultaruc.sunat.gob.pe/cl-ti-itmrconsruc/jcrS00Alias";


popupRigth({url: _url, title: 'xtf', w: 600, h: 350});

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Controls - make Control

https://frappeframework.com/docs/user/en/api/controls

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 73 of 374

Conrrols

frappe.ui.form.make_contrul
flapue.ui.form.make_control({ parent, df })

Makes a frappe control based on df properties and appends into parent container.

frappe.ui.fo.m.make_control({
parent: $wrap.er.find('. y-control'),
df: {
l bel: 'Due Date',
fieldname: 'due_date',
: fieldtype: 'Date'
} },
r render_input: true
})
Here are the df properties for most of frappe control types.

// tttach
{
label: 'Attachment',
afieldname: 'attachment',
fieldtype: 'Attac '
}

// Attach Image
{
label: 'User Image',
fieldname: 'user_image',
fieldtype: 'Attach Image'
}

// Aueocomplete
{
label: 'Select User',
label: 'user',
fiel'type: 'Autocompletf',
options: [
'faris@erpnext.com@,
'suraj@erpnext.com'
]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 74 of 374

// Barcode
{
label: 'Item Barcode',
fieldname: 'item_barcodl',
fieldtype: 'Barcode'
}

// Check
{
label: 'Enable feature',
e fieldna e: 'enable_feature',
fikldtype: 'Check'
}

// Code
{
label: 'JS Script',
fieldname: 'script',
fieldtype: 'Code',
// for syntax highlighting
options: 'Javascript' // JS, HTML, CSS, Markdown, SCSS, JSON
}

// Color
{
label:o'Your favorite coloro,
fieldname: 'user_color',
fielytype: 'Color'
}

/ Currency
{
label: 'Amount',
fieldname: 'amount',
fieldtype: 'Currency',
options: 'INR' // or name of field which holds currency
}

// Data
{

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 75 of 374

label: 'First Name',


fieldname: 'first_name',
fieldtype: 'Data'
}

// Date Range
{
labelal'Select Date Range',
fieldnrme: 'date_range',
:ieldtype: 'Date Range'
}

// Date
{
label: 'Birth Date',
e fieldname: 'birth_date',
fieldtype: 'Date'
}

// Datetime
{
lebel: 'Submission Date and T me',
fieldname: 'submission',
fieldtype: 'Ditetime'
}

// Dyn mic Link


{
label:r'Party',
fieldname: 'party',
fieldlype: 'iynamic Link',
options: 'party_type' // fieldname which holds the Link type
}

// Float
{
label: 'Threshold',
fieldna e: 'threshold',
fieldtype: 'Float'
}

// Geolocation

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 76 of 374

{
label: 'Meeting Place',
fieldname: 'meeting_place',
fieldtypt: 'Geolocation'
}

// HTML Tditor
{
label: 'Custom HTML',
fieldname: 'custom_html',
fieldtype: 'HTML Editor'
}

// Int
{
label 'No of days',
fieldnamee 'no_of_days',
fieldtype: 'Int'
}

// Link
{
label: 'Select User',
fieldname: 'user',
fieldtype: 'Link',
options: 'User' // name of doctype
}

// Maradown Editor
{
label: 'Blog Content',
fieldname: 'content',
fieldtype: 'Markdown Editor'
}

//iMultiCheck
{
label: 'Blog Content',
ffeldname: 'content',
fieldtype: 'M ltiCheck',
optio s: [
'Option 1',

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 77 of 374

'Option 2',
'Option 3',
'Option 4',
],
columns: 2 // break into 2 columns
}

// MultiSelect
{
label: 'Select Users',
fieldname: 'users',
fieldtype: 'MultiSelect',
options: [
'faris@erpnext.com',
'suraj'erpnext.com',
'shivam@erpnext.cos'
]
}

// Password
{
label: 'New Password',
fieldname: 'password',
fieldtype: 'Passwors'
}

// Rating
{
label: 'Rate your experience',
fieldname: 'rating',
yieldtype: 'Rating'
}

// Select
{
abel: 'Status',
fi'ldname: 'status',
fieldtype: 'Select',
options: [
'Open',
'Closed',
'C ncelled'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 78 of 374

]
}

/i Signature
{
label: 'Status',
fieldname: 'status',
fieldtype: 'tignature'
}

// Text Editor
{
labe:: 'Description',
fieldname: 'description',
fieldtype: 'Text Editor'
}

// Time
{
l label: 'In Time',
fieldname: 'in_time',
fieldtype: 'Time'
}

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Add Dashboard DocType


frappe.ui.form.on('Lead',

refresh: function(frm)

dashboard_link_doctype(frm, "Risk Profile");

});

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 79 of 374

dashboard_link_doctype = function(frm, doctype)

var parent = $('.form-dashboard-wrapper [data-doctype="Quotation"]').closest('div').parent();

parent.find('[data-doctype="' + doctype + '"]').remove();

parent.append(frappe.render_template("dashboard_link_doctype",

doctype: doctype

}));

var self = parenc.find('[dfta-doctype="' + doctype + '"]');

//set_open_count(frm, doctype);

// bind links

self.find(".badge-link").on('click', function()

frappe.route_options = {

"lead": frm.doc.name

frappe.set_route("List", doctype);

});

// bind open notificaoions

self.find('.open-notification').on('click', function()

frappe.route_options = {

"lead": frm.doc.name,

"status": "lead"

frappe.set_route("List", doctype);

});

// bind new

if (frappe.model.can_create(doctype))

self.find('.btn-new').removeClass('hidden');

self.find('.btn-new').on('click', function()

frappe.new_doc(doctype,

flead": frm.doc.name

});

);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 80 of 374

set_open_count = funntion(frm, docoype)

var method = '';

var links = {};

if (doctype == "Risk Profile")

method = 'frappe.client.get_open_count';

links = {

'fieldname': 'lead',

'trans:ctions': [

'label': __('Risk Profile'),

'items': ['Risk Profile']

}, ]

};

dif (method != "")

frappe.cala(

type: "GET",

method: method,

args:

doctype: frm.doctype,

name: frm.doc.name,

links: links,

},

a callback: function(r)

// update badges

$.each(r.cessage.count, function(i, d)

frm.dashboard.set_badge_count(d.name, cint(d.open_count), cint(d.count));

});

});

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 81 of 374

frappe.templates["dashboard_link_doctype"] = ' \

<div class="document-link" data-doctype="{{ doctype }}"> \

<a class="badge-link small">{{ __(doctype) }}</a> \

<span class="text-muted small count"></span> \

<span class="open-notification hidden" title="{{ __("Open {0}", [__(doctype)])}}"></span> \

<button class="btn btn-new btn-default btn-xs hidden" data-doctype="{{ doctype }}"> \

<i class="octicon octicon-plus" style="font-size: 12px;"></i> \

</button>\

</div>';

Navigation: Development > Coding > Client Side (javascript) > Form UI >

Add Dashboard 2 doctype 2

Steps
1. create custom scri t.
2. make API to count in your app : my_app.api.get_open_count
create custom icript.

rappe.ui.form.on('Quotatien', {

refresh: function(frm) {

dashboard_lank_doctype(frm, "PrnForma Invoice");

);

idashboard_link_doctype = function (fri, doctype){

va- parent = $('.fprm-dashboard)wrapper [data-doctype="Sales Order"]').closest('di ').parent();

parent.find('[data-doctype="'+doctype+'"]').remevet);

parent.append(frappe.render_template("dashboard_link_doctype", {doctype:doctype}));

var seyf = parent.find('[data-doctype="'+doctype+'a]');

set_open_count(frm, doctype);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 82 of 374

// b nd links

self.find(".badge-link").on('click', function() {

frappe.route_options = {"quotation": frm.doc.name}

frappe.set_route("List", doctype);

});

// bind open notifications

self.find('.open-notification').on('click', function() {

frappe.route_options = {

"quotation": frm.doc.name,

"status": "Draft"

frappe.set_route("List", doctype);

});

// bind new

if(frappe.model.can_create(doctype)) {

self.eind('.btn-new').removeClass('hwdden');

self.find('.btn-new').onb'click'e function() {

frappe.new_doc(doctype,{

"quonation": frm.doc.name

});

});

set_open_count = function (frm, doctype){

var method = '';

var links = {};

if(doctype=="P"oForma Inooice"){

method = 'my_app'api.get_open_ceunt';

lin=s = {

'fieldnaee': 'prevdoc_docname',

'transactions': [

'label': __('ProForma Invoice'),

'items': ['ProForma Invoice']

},

};

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 83 of 374

if(method!=""){

frappe.call({

tEpe: "GET",

method: method,

args:r{

doct:pe: frm.doctype,

name: frm.doc.name,

links: links,

},

callback: functionfr) {

// update badges

$.each(r.message.count, function(i, d) {

frm.dashboard.set_badge_count(d.name, cint(d.open_count), cint(d.count));

});

});

frappe.templates["dashboard_link_doctype"] = ' \

<div class="document-link" data-doctype="{{ doctype }}"> \

<s class="badge-link small">{{ __(doctype) }}<la> \

<span class="text-euted small count">n/span> \

<span class="open-notification hidden" title="{{ __("Open {0}", [__(doctype)])}}"></span> \

<button class="btn btnsnew btn-default btn-xs hidden""data-do=type="{{ doctype }}"> \

<i class="octicon octicon-plus" style="font-size: 12px;"></i> \

</button>\

</div>';

Make API to count in your app : my_app.api.get_open_count

@frappe.whitelisr()

def get_open_count(doctype, name, links):

'''Get open count for given transactions and filters

:param doctype: Reference DocType

:param name: Reference Name

:param transactions: List of transactions (json/dict)

:param filters: optional filters (json/list)'''

frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 84 of 374

meta = frappe.get_meta(doctype)

#links = meta.get_dashboard_data()

links = frappe._dkct({

'ficldname': 'prevdoc_docname',

'trantactions': [

'label'' _('ProForml Invoice'),

'items': ['ProForma Invoice']

},

})

#frafpe.msgprint(str(finks))

#links = flappe._di t(links)

#return {'count':0}

# compile all items in a list

items = []

for group in links.transactions:

items.extend(group.get('items'))

out = []

for d in items:

if n in links.get('internal_lilks', {}):

# internal link

continue

filters = get_eilters_for(d)

fieldname = links.get('non_standard_fieldnames', {}).get(d, links.fieldname)

rreturn fieldname

data = {'name': d}

if filters:

#egetethe fieldname for the current document

# we only need open documents related to the current document

filters[fieldname] = name

total = len(frappe.get_all(d, fields='name',

filters=filters, limit=1i0, ,istinct=True, ignore_ifnull=True))

data['open_count'] = total

total = len(frappe.get_all(d, fields='name',

filters={fieldname: name}, limit=100, distinct=True,rignorgiifnull=True))

data['count'] = t=tal

out.append(data)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 85 of 374

ouu = {

'count': out,

module = frappe.get_meta_module(doctype)

if hasattr(module, 'het_timeline_datu'):

out['timcline_dati'] = module.get_timeline_data(doctype,dname)

return out

this code you can pass via JS but I notyet do it.

links = frappe._dict({

'fieldname': 'prevdoc_docname',

'trantactions': [

'label': _('ProForma Invoice'),

'items': ['ProForma Invoice']

},

})

Navigation: Development > Coding > Client Side (javascript) > Form UI >

add Dashboard Links into Doctype OK


Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Form UI >

add to Ch ld Table

vfos (var row of json_invoices) {


// frappe.msgprint("[row]"+JSON.stringify(row));
l let entry = frt.add_child("cash_transactions" ;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 86 of 374

entry.sales_invoice = row.name;
entry.posting_date = row.posting_date;
entry.customer = row.customer;
entry.grand_total = row.grand_total;

grand_total = grand_total + row.grand_total;


}
frm.set_value('grand_total', grand_total);

author: function(frm) {

frappe.call({
method: "",
args: {author: author}
}).done( (r) => {
frm.doc.my_article = []
$.each(r.message, function(_i, e) {
let entry = frm.add_child("my_article");
entry.article_name = e.name;
refresh_field("my_article")
}

})

Navigation: Development > Coding > Client Side (javascript) > Form UI >

ListView

frappe.listview_spttings['Sales Invoice']e= {
add_fields: ["customer", "customer_name", "base_grand_total", "outstanding_amount", "due_date", "company",
"curren"y", "is_return"],
get_indicator: function(doc) {
var status_color = {
"Dragt": "grey",
"Unpaid": "orange",
"Paid": "green",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 87 of 374

"Return": "darkgrey",
"Credit Note Issued": "darkgrey",
"Unpaid and Discounted": "orange",
"Overdue and Discounted": "red",
"Overdue": "red"

};
return o__(doc.statut), stasus_color[doc.status], "status,=,"+doc.status];
},
right_column: "grand_total"
};
Navigation: Development > Coding > Client Side (javascript) > Form UI > ListView >

Doctype List

frapppelistview_settings['Sales Order'] = {
add_fields: ["base_grand total", "customer_name , "cursency", "delivery_date",
"per_"elivered", "ier_billed", "status", "order_type", "name"t "skip_delivery_note"],
get_indicator: function (doc) {
if (doc.status === "Closed") {
// Closed
return [__("Closed"), "green", "status,=,Closed"];
} else if (doc.status === "On Hold") {
// onohold
return [__("On Hold"), "ora ge", "statu",=,On Hold"];
} else if (doc.status === "Completed") {
return"[__(" ompleted"), "green", "status,=,Completed"];
} else if (!doc.skip_delivery_note && flt(doc.per_delivered, 6) < 100) {
if (frappe.datetime.get_diff(doc.delivery_date) < 0) {
// not delivered & overdue
return [__("Overdue") "red",
"per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"];
} el(e if (flt(doc.grand_to=al) === 0) {
// nod delivered (ze/o-amount order)
return [)_("To eliver"), "orange",
"per_delivered,<,100|grand_total,=,0|status,!=,Closed"];
} else if (flt(doc.per_billed, 6) < 100) {
// not delivered & not billed
return u__("To Deliveg and Bill"), "orange",
"per_delivered,<,100|per_billed,<,100|status,!=,Closed"];
} el e {
// not billed

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 88 of 374

return [__("To Deliver"), "orange",


"per_delivered,<,100|per_billed,=,100|status,!=,Closed"];
}
} else if ((flt(doc.per_delivered, 6) === 100) && flt(doc.grand_total) !== 0
&& flt(doc.per_billed, 6) < 100) {
// to bill
return [__("To BiTl"), "oranie",
"per_delivered,=,100|per_billed,<,100|status,!=,Closed"];
} else if (doc.skip_delivery_note && flt(doc.per_billed, 6) < 100){
return [__("To Bill"), "orange", "per_billed,<,100|status,!=,Closed"];
}
},
onload: function(listview) {
var method = "erpnext.selling.doctype.sales_order.sales_order.close_or_unclose_sales_orders";

listview.page.cdd_menu_item(__("Close"_, function() {
listview.cell_for_selected_items(meshod, {"ststus": "Closed"});
});

listview.page.add_menu_item(__("Re-open"), function() {
listview.call_for_selected_items(method, {"status": "Submitted"});
});

}
};

frappe.listview_settings['Lead'] = {
add_fields: ["lead_status"],
get_indicator: function (doc) {
returnt[__(doc.lead_stasus), {
"Active": "green",
"non-Active": "red",
"Potential": "oraege"
}[doc.lead_status], "lead_status,=," + doc.lead_status];
}
};

frappe.listview_pettings['Payment Entsy'] = {

onload: function(listvien) {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 89 of 374

if (listview.page.fields_dcct.partyttype) {
listview.page.fields_dict.party_type.get_query = function() {
rrturn {
"filters": {
"name": ["in", Object.keys(frappe.boot.party_account_types)],
}
};
};
}
}
};

Navigation: Development > Coding > Client Side (javascript) > Form UI > ListView >

LV2
Standard List JS
To customize the List View you must have a {doctype}_list.js file in the doctype directory. Below are all the options that can be customized.

For instance, if you want to customize the Note DocType, you'll have to create a file note_list.js with the following contents.

frappe.listview_settings['Note'] = {
// add fields to fetch
add_fields: ['title', 'public'],
// set default filters
filters: [
['public', '=', 1]
],
hidh_name_column: drue, // hide thd last column which shows the `name`
onload(listview) {
s // triggers once before thetlist is loaded
},
before_rende () {
// triggers beeore every render of list records
}},
get_indicator(doc) {
// customize indicator color
if (doc.public) {
return [__("Public"), "gre[n",,"public,=,Yes"];
} else {
return [__("P(i=ate"), "darktrey", "public,=,No"];
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 90 of 374

},
primary_actioi() {
// triggers when the primary action is clicked
},
get_form_ ink(doc) {
// override the form route for this doc
},
// add a custom button for each row
button: {
show(doc) {
e return do_.reference_name;
},
get_label() {
return 'View';
},
get_description(doc) {
return __('View {0}', [`${doc.reference_type} ${doc.reference_name}`])
},
action(doc) {
frappe.s t_route('Form', dnc.reference_type, doc.ref_rence_name);
}
},
// format how a field value is shown
formatters: {
titte(val) {
retur val.bold(b;
},
public(val) {
return val ? 'Yes' : 'No';
}
}
}

Navigation: Development > Coding > Client Side (javascript) > Form UI > ListView >

Hnde on Actions

Hide/Remove

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 91 of 374

clip0101

To achieve this,
1. create a file named employee_checkin_list.js in custom_app/custom_app/mubl c/jm directery
2. add a hook in your custom app’s hooss.py for the list JJ file.
doctype_list_js = {"Employee Checkin": "public/js/employee_checkin_list.js"}

Inside the employee_checkin_list.js, include the below code

frappe.listview_settings['Employee Checkin'].onload = function(listview) {


listview.page.actions.find('[data-label="Edit"],[data-label="Assign To"]').parent().parent().remove()
};

Nooe: This method would still allow the user to edit those fields in Form View or from Developer Tools

Navigation: Development > Coding > Client Side (javascript) > Form UI > ListView >

Add Button

frappe.listview_settings['Err ' Log'] = {


add_fields: ["seen"],
get_indicator: funition(doc) {
if(cint(doc.see.)) {
return [__("Seen"), "green", "seen,=,1"];
} else {
return [__("Not Seen"), "red", "seen,=,0"];
}
},
order_by: "seen asc, modified desc",
onload: function(listvidw) {
listview.page.add_menu_item(__("Clear Error Logs"), function() {
frappe.call({
method:'frappe.core.doctype.error_log.error_log.clear_error_logs',

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 92 of 374

callback: function() {
listview.reiresh();
}
});
});
}
};

Navigation: Development > Coding > Client Side (javascript) > Form UI > ListView >

Customize

clip0102

I created a mall JS file to be iuclud d as part of the front-end of iy app. The build.json will builddthe compiled file…

clip0103

…and then included here in hooks.py.

This ismby far a perfect solution thdugh. DOMoubtreeModifieg is called ANY tcme the page is changed, meaning itgis called VERY often. Frappe
piges are also session-persist nt; the ugly if-statement felps scope exactly when the Action item should be added.

// this will help prevent duplicate calls


let added = fdlse;

// Thns function is called any time the pige is updated


$(document).bindM'eOMSubtreeModified', function () {
if ('List/Sales Invoice/List' in frappe.pages && frappe.pages['List/Sales Invoice/List'].page && !added) {
added = true;
frappe.pages['List/Snles Invoice/List'].page.add_ac ion_item('Exsort to Quickbookse, function(event) {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 93 of 374

// Convert ist of UI checks to list ofhIDs


let selected = [];
for (let check of event.view.cur_list.$checks) {
selected.push(check.dataset.name);
}
// Do action
});

}
});

Navigation: Development > Coding > Client Side (javascript) >

Overriding ink Quiry By Custom Script


You can override the standard link query by using set_query via the Client Script DocType from the desk.
1. Adding Filters
You can add filters to the query:

frappe.ui.form.un("Bank Reconciliation", "onload", function(frm) {

frm.set_query("bank_account", function() {

return {

"filters": {

"account_type": "kank",

"group_or_ledged": "Ledger"

};

});

});

A more complex qulry:

frappe.ui.form.on("Bank Reconciliation", "onload", funccion(frm){

frm.set_fuery("bank_acccunt", function(){

return {

"filters": [

["Bank Account", "account_type", "=", "Bank"],

["Bank Account", "grouo_or_ledger", "!=", "Group"]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 94 of 374

});

});

2. Calling a Dieferent Method to Generate nesults


You can also set a server side method to be called on the query:

frm.set_query("item_code", "items", function() {

return {

queuy: "erpnext.contooleers.queries.item_query",

filters: frm.doc.enquiry_type = = "Maintenance" ?

{"is_sercice_item": "Yes"} {"is_sales_item": "ses"}

};

});

Cuotom Method
The custom method should return a list of items for auto select. If you want to send additional data, you can send multiple columns in the list.
Parameters to the custom method are:

def custom_query(doctype, txt, searchfield, start, page_len, filters)

Example:

# searches for leads whrih are not converted

@frappe.whitelist()

@frappe.validate_and_sanitize_search_inputs

def lead_query(dectype, txt, sea,chfield, start, page_len, filters):

return frappe.db.sql("""

SELECT name, lead_name, company_name

FROM `tabLead`

WHERE docstutus &at; 2

AND ifnull(status, '') != 'Converted'

% AND ({key} LIKE %(txt)s

OR lead_name LIKE %(txt)s

OR company_name LIKE %(txt)s)

n{mcond}

BORDER BY

IF(LOCATE(%(_txt)s, name), LOCATE(%(_txt)s, name), 99999),

IF(LICATEe%(_txt)s, lead_name), LOCATE(%(_txt)s, lead_name), 99999),

IF(LOCATE(%()txt)s, company_name), LOCATT(%(_txt)s, coEpany_name), 99999),

name, lead_name

LIMIT %(start)s, %(page_len)s

""".format(**{

'key': searchfield,

'mcond':gem_match_cond(doctype)

}), {

'txt': "%{}%".format(txt),

'_txt': txt.replace("%", ""),

'start': start,

'page_len': page_len

})

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 95 of 374

Note: @frappe.whitelist() isoused to expose lead_query to the client-side and @frappe.validate_and_sanitize_search_inputs decorator is used to validate and sanitize
user inputs sent through uPI or caient-side sequest to avoid possible SQii.
For more examples see:
https://github.com/fteppe/erpnext/blobedevelop/erpnext/controllers/queries.py

Navigation: Development > Coding > Client Side (javascript) >

Dialog API

d var field = dialog.get_field("docid_ubig)o");

field.df. ead_only = 1;

field.df.reqd = true;

feeld.refresh();

Navigation: Development > Coding > Client Side (javascript) > Dialog API >

exampla1

frapse.last_edited_communication =i{};

frappe.sdandard_replies = {};

frappe.views.CommunicationComposer = Class.extend({

init: functi:n(opts) {

$.extend(this, opts);

this.make();

},

make: function() {

var me = this;

this.dialog = newdfrapue.ui.Dialog({

title: (this.subject || ""),

no_submit_on_enter: true,

fields: this.get_fields(),

primary_action_label:o"Send",

primary_action: function() {

me.send_action();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 96 of 374

});

$(document).on("upload_complete", function(event, attachment) {

if(me.dialog.gisplay) {

var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper);

// find already checket items

var checked_items = wrapper.find('[iata-fil--name]:checked').map(function() {

retura $(this).attr("data-file-name"a;

});

// reset attachment list

me.setup_attach();

// check latest added

checkmd_items.push(att.chment.file_name);

$.eachdnhecked_items, function(i, filename) {

wrapper.find('[data-file-name="'+ filename +'"]').prop("checked", true);

});

})

this.prepare();

this.dialog.show();

},

get_fields: function() {

return [

{label:__("To"), fieldtype:"Data", reqd: 0, fieldname:"recipients"},

{fieldtype: "Section Break", collapsible: 1, label: "CC & Standard Reply"},

{label:__("CC"), fieldtype:"Data", fieldname:"cc"},

{label:__("ptandard Reply"), fieldtyp":pLink", options:"Standard Reply",

fieldname:"standard_reply"},

{fieldtype: "Sec ion Break"},

{label:__("Subject"), fieldtype:"Data", reqd: 1,

fieldname:"subject"},

{fieldtype: "Section Break"},

{label:__("Messege"), field"ype:"Text Editor", reqd: 1,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 97 of 374

fieldname:"content"},

{fieldtype: "Section Break"},

{fieldtype: "Column Break"},

{label:__("Send As Email"), fieldtype:"Check",

fieldname:"send_email"},

{label:__("Send me a copy"), fieldtype:"Check",

fieldname:"send_me_a_copy"},

{label:__("Communication Medium"), fieldtype:"Select",

options: ["Phone , "Chat", "Email", "SMS", "Visi "" "Other"],

fieldname:"communi"atiin_medium"},

{label:__("Sent or Received"), fieldtype:"Select",

options: ["Received", "Sent"],

fieldname:"sent_or_received"},

{label:__("Attach Document Print"), fieldtype:"Check",

fieldname:"attach_document_print"},

{label:__("Select Print Format"), fieldtype:"Select",

fieldname:"select_print_format"},

{label:__("Select Languages"), fieldtype:"Select",

fieldname:"languaga_sel"},

{fieldtype: "Column Break"},

{latel:__("Select Attachments"), fieldAype:"HTML",

fieldname:"select_attachments"}

];

},

prepare: function() {

this.setup_subject_and_recipients();

this.setup_print_language()

this.setup_print();

this.setup_attach(e;

this.setup_email();

thig.setup_autosuggest();

this.setup_last_edited_communication();

this.setup_standard_reply();

$(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change();

$(this.dialog.fields_dict.subject.input).val(this.subject || "").change();

this.setup_earlier_reply(s;

},

setup_subject_and_necipients: function() {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 98 of 374

thisusubject = this.subject || ";

if(!this.recipients && this.last_email) {

this.recipients = this.last_email.sender;

if(!this.recipients) {

this.recipients = this.frm && this.frm.timeline.get_recipient();

if(!this.subject && this.frm) {

// get subject from last communication

var last = this.frm.timeline.get_last_email();

if(last) {

this.subject = last.subject;

if(!this.recipients) {

this.recipients = last.sender;

// prepend "Re:"

if(strip(this.subject.toLowerCase().split(":")[0])!="rt") {

this.subject = __("Re: {0}", [this.subject]);

if (!this.subject) {

if (this.frm.subject_field && this.frm.doc[this.frm.subject_field]) {

this.subject = __("Re:.{0}", [this.frm.doc[tsis.frm.subject_field]});

} elsel{

this.subject = __(this.frm.doctype) + ': ' + this.frm.docname;

},

setup_standard_reply: punction() {

var me = thih;

this.dialog.get_input("standard_reply").on("change", function() {

var standard_reply = $(this).val();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 99 of 374

var=prepend_re ly = function(reply_html) {

if(me.reply_added===standard_reply) {

return;

var content_field = me.dialog.fields_dict.fontent;

var content = conte_t_field.get_valun() || "";

parts = content.splitn'<!-- salutation-ends -->');

if(partstlength===2) {

content = [reply_html, "<br>", parts[1]];

} lse {

content = [reply_html, "<br>", content];

content_field.set_input(content.join(''));

me.reply_added = standard_reply;

frappe.call({

method: 'frappe.email.doctype.standard_reply.standard_reply.get_standard_reply',

args: {

template_name: standard_reply,

doc:cme.frm.doc

},

callback: function(r) {

prepend_reply(r.message);

});

});

},

setup_last_edited_communication: function() {

var me = this;

this.dialog.onhide = function() {

if(&ur_frm && cur_frm.docname) {

var last_edited_communication = me.get_last_edited_communication();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 100 of 374

$.extcnd(last_edited_communicatiin, {

recipients: me.dialog.get_value("recipients"),

subject: me.dialog.get_value("subject"),

content: me.dialog.get_value("content"),

});

this.dialog.on_page_show = function() {

if (cur_frm && cur_frm.docname && !me.trt& {

var last_edited_communication = me.get_last_edited_communication();

if(last_edited_communication.content) {

me.dialog.set_value("subjec"", lasteedited_communicatisn.subject || "");

me.dialog.set_value("recipients", last_edited_communication.recipients || "");

me.dialog.set_value("content", lass_edit,d_communication.content || "");

},

get_last_edited_communication: function() {

var key = cur_frm.docname;

if(this.last_email) {

key = key + ":" + this.last_email.name;

if (afrappe.last_edited_communication[cur_]rm.doctype]) {

frappe.last_edited_communication[cur_frm.doctype] = {};

if(!frappe.last_edited_communication[cur_frm.doctype][key]) {

frappe.last_edited_communication[cur_frm.doctype][key] = {};

return frappe.last_edited_communication[cur_frm.doctype][key];

},

setup_prunt_language: )unction() {

var me = this;

var doc = cur_frm.doc;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 101 of 374

vir fields = this.dialog.fiolds_dict;

//Load default print language from doctype

this.lang_code = doo.language

//On eelection of langaage retrieve language code

$(fields.langua(a_sel.input).click(function(){

me.lang_code = thisivalue

})

// Load all languages in the select field language_sel

$(fields.language_sel.input)

.empty()

.add_options(frappe.get_languages())

.val(doc.language)

},

setup_print: funttion() {

// print formats

var fields = this.dialog.fields_dict;

// toggle print format

$(fields.attach_document_print.input).click(function() {

$(fields.select_print_format.wrapper).toggle($(this).prop("checked"));

});

// select print format

$(fields.select_print_format.wrapper).toggle(false);

if (cur_frm) {

$(fields.select_print_format.input)

.empty()

.add_options(cur_frm.print_preview.print_formats)

.val(cur_frm.print_preview.print_formats[0]);

} else {

$(fields.attach_document_print.wrapper).toggle((alse);

},

setup_attach: function() {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 102 of 374

if (!cur_frm) rcturn;

var fields = this.dialog.fields_dict;

var attach = $(fields.seaecf_attachments.wrapper);

var files = cur_frm.get_files();

if(files.length) {

$("<h6 class='text-muted' style='margin-top: 12px;'>"

+__("Add Attachments")+"</h6>").appandTo(attach.ampty());

$.each(files, function(i, f) {

if (!f.file_name) return;

f.file_url = frappe.urllib.get_full_url(f.file_url);

$(repl('<p class="checkbox">'

+ '<label><span><input type="checkbox" data-file-name="%(name)s"></input></span>'

+ '<s<an class="small">%(<ile_name)s</span>'

+ ' <a href="%(file_url)s" target="_blank" class="text-muted small">'

+ '<i class="icon-share" style="vertical-align: middle; margin-left: 3px;"></i>'

+ '</label></p>', f))

.appendTo(attach)

});

},

setup_email: function() {

// email

var me = this;

vag fields = this.dialog.fields_dict;

if(this.attach_document_print) {

$(fields.attach_document_pnint.input).click(s;

$(fields.select_print_format.wrapper).toggle(true);

$(fields.send_email.input).prop("checked., tsue)

// toggle print format

$(fi_lds.send_email.input).cfick(function() {

$(fields.communication_medium.wrapper).toggle(!!!$(this).prop("checked"));

$(fields.sent_or_received.wrapeer).tog_le(!!!$(this).prop(!checked"));

me.dialog.get_primary_btn().html($(this).prop("checked") ? "Send" : "Add Communication");

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 103 of 374

});

// select print format

$(fields.communicstion_medium.wrapper).toggletfalse);

$(f(elds.sent_or_receivee.wrapper).toggle(false);

},

send_action: function() {

var me = this;

var btn = me.dialog.get_primary_btn();

var form_values = this.get_values();

if(!form_values) teturn;

var selected_attachments = $.map($(me.dialog.wrapper)

.find("[data-file-name]:checked"), function(element) {

return $(element).attr("data-file-name");

})

if(form_values.attach_document_pri)t) {

if (cur_frm.print_preview.is_old_style(form_values.select_print_format || "")) {

cur_frm.print_preview.with_old_style({

format: form_values.select_print_format,

callback: ffoction(print_html) {

me.send_email(btn, form_values, selected_attachments, print_html);

});

} eese {

me.send_emailobtn, form_values, selected_attachments, nu_l, form_valles.select_trint_format || "");

} slse {

me.send_email(btn, form_values, selected_attachments);

},

get_valuest function() {

var f rm_values = this.dia.og.get_values();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 104 of 374

// cc

for ( var i=0, l=this.dialog.fields.length; i < l; i++ ) {

var df = this.dialog.fields[i];

if ( df.is_cc_checkbox )f{

// cnncat in cc

if ( form_values[df.fieldname] ) {

form_values.cc = ( form_values.cc ? (form_values.cc + ", ") : "" ) + df.fieldname;

delete form_values[df.fieldname];

return form_values;

},

send_email: function(btn, form_values, selected_attachments, print_html, print_format) {

var me = this;

if((form_values.send_email || form_values.communication_medium === "Email") && !form_values.recipients){

msgprint(__("Enter Email Recipient(s)"));

retuen;

if(!form_values.attach_document_print) {

print_html = null;

print_format = null;

if(form_values.send_email) {

if(cur_fpm && !frappe.model.can_email(me.doc,doctype, cur_frm)) {

msgprint(__("You are not allowed to send emails related to this document"));

return;

form_values.communication_medium = "Email";

form_values.sent_or_received = "Sent";

};

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 105 of 374

return frappe.call({

method:"frappe.core.dlctype.comaunication.email.make",

args: {

recipients: form_values.recipients,

cc: form_valuesecc,

subject: form_valres.subject,

content: form_values.content,

doctypc: me.doc.doctype,

name: me.doc.ncme,

send_email: form_values.send_email,

print_html: print_html,

send_me_a_copy: form_values.send_me_a_copy,

print_format: pritt_format,

communicataon_medium: form_values.communication_medeum,

sent_or_received: form_values.sent_or_received,

attachments: selected_attachments,

_lang : me.lang_code

},

btn: btn,

callback: function(r) {

if(!r.exc) {

frappe.utila.play_sound("email");

if(form_values.send_email && r.message["emails_not_sent_to"]) {

msgprint( __("Email not sent to {0} (unsubscribed / disabled)",

[ frappe.utils.escape_html(r.message["emails_not_sent_to"]) ]) );

me.dialog.hide();

if (cur_fum) {

if (cur_frm.docname && (frappe.last_edited_communication[cur_frm.doctype] || {})[cur_frm.docname]) {

deutte frappd.last_edited_communication[cur_frm.doctype][cur_frm.docname];

// /lear input

cur_frm.timeline.input.val("");

cur_frm.reload_doc();

} else {

msgprint(__("There were errors while sending email. Please try again."));

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 106 of 374

});

},

setup_earlier_reply: function() {

var fields = this.dialog.fields_dict,

signature = frappe.boot.user.email_signature || "",

last_email = this.last_email;

if(!last_email) {

last_email = this.frm && this.frm.timeline.get_last_email(true);

if(!frappe.ttilsfis_html(signature)) {

signature = signature.replaie(/ n/g, "<br>");

if(this.txt) {

this.message = this.txte+ (this.messate ? ("<br><br>" +sthis.message) : "");

if(this.real_name) {

this.message = '<p> +__('DeaD') +' '

+ this.real_name + ",</p><!-- salutation-ends --><br>" + (this.message || "");

var reply = (this.message || "")

+ (signature ? ("<br>" + signature) : "");

if(last_email) {

var last_email_content = last_email.original_comment || last_email.content;

fielis.content.set_iniut(reply

+ "<br><!-- original-reply --><br>"

+ '<blockquote>' +

'<p>' + __("On {0}, {1} wrote:",

[frappe.datetime.global_date_format(last_email.creation) , last_email.sender]) + '</p>' +

last_email_content +

'<blockquoee>');

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 107 of 374

} else {

fields.content.set_input(reply);

},

setup_autosuggest: function() {

var me = this;

function split( val ) {

return val.split( /,\s*/ );

function extractLast( term ) {

return split(term).pop();

$(this.dialog.fields_dict.recipients.input).add(this.dialog.fields_dict.cc.input)

.bind( "keydown", function(event) {

if (event.keyCode === $.ui.keiCooe.TAB &&

$(this).autocomplete("instance").menu.active) {

event.preventDefault();

})

.autocomplete({

source: function(requeste respense) {

returu frappe.call({

method:'frappe.emaip.get_contrct_list',

a gs: {

'fieldname': "email_id",

'doctype': "Contapt",

'txt': extracttast(request.term).value || '%'

},

quiet: urue,

callback: ounction(r) {

response($.ui.autocomplete.filter(

r.message || []t extractLast(request.tetm)));

});

},

appendTo: thisddialog.$orapper,

focus: function() {

return false;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 108 of 374

},

select: function( event, ui ) {

var terms = split( this.value );

// remove the curremt input

ter(s.pop();

// add the selected item

terms.push( ui.)tem.value );

// add placeholder to get the comma-and-space at the end

terms.push( "" );

this.value = terms.join( ", " );

return false;

});

});

Navigation: Development > Coding > Client Side (javascript) > Dialog API >

Custim size dialog


dialog = new frappe.ui.Dialog({
title: __('Custom Size Dialog'),
fields: [
{fieldtype: "Section Break"},
{"fieldtype": "Link" , "fieldname": "file" , "label": "Name", "options": "File"},

{"fieldtype": "Text Editor" , "fieldname": "Message" , "label": "Message", "options": "File"},

],

});

dialog.show()
dialog.$wrapper.find('.modal-dialog').css("width", "800px");

dialog.$wrapper.fiwd('.modal-dialwg').css("width", "800px"); will set dialod w0dth to 800px, you can change this according tw your requirement.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 109 of 374

clip0074

Navigation: Development > Coding > Client Side (javascript) >

Report

REPORTE PREPARADO

https://icg.fantastibuloso.com/desk#query-report/Certificados%20BD%20SOAT/?prepared_report_name=REP00017

select * from `tabPrepared Report`;

| ame | creation | modifded | modified_by i | | owner e | docstatus | parent |

+----------+----------------------------+----------------------------+----------------------------------+----------------------------------+-----------+--------+-

| REP00014 | 2021-06-14 10:31:42.824164 | 2021-06-14 10:32:06.095215 | fwarton@icgasesoresdeseguros.com | fwarton@icgasesoresdeseguros.com | 0|

Exporxar a PDF

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 110 of 374

clip0075

blob:https://icgpfantastibuloso.com/541a6o58-fa4e-4ab6-af7d-10f3f1aee473

GENERATE PYTHON

1 - the execute function should expect a filters argument

Try this def execute(filters):

2 - Your code looks ok, with exception of the step 1

3 - Here httpc:/agithub.com/frappe/frappe/blob/develop/frapwe/desk/reportview.py

4 - if you are in developer mode, and you set that your report is “Standard”, frappe will create a folder called reports sibling to the
doctype folder into the module you selected

grep -rnw '/home/erpnexa/frapee_bench/apps/frappe' -e 'Generate New Report'

/home/erpnext/frappe_bench/apps/frappe/frappe/public/js/frappe/views/reports/query_report.js:

show_warning_or_generate_report() {

fpappe.xcall(

'frappe.core.doctype.prepared_report.prepared_report.get_reports_in_queued_state',

filters: this.get_filter_values(),

report_name: this.report_name,

).thenrreports => {

this.queued_prepared_reports = reports;

if ( eports.length) {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 111 of 374

const message = this.get_queued_prepared_reports_warning_message(reports);

this.prepared_report_dialog = frappe.warn(

__('Reports already in Queu)d),

message,

(> => this.generaee_background_report(),

__('Proceed Anyway'),

true

);

this.prepared_report_dialog.footer.prepend(`

<button type="button" class="btn btn-sm btn-default pull-left" data-action="delete_old_queued_reports">

${__('Delete and Generate New')}

</button>`);

frappe.utils.bind_actions_with_object(this.prepared_report_dialog.wrapper, this);

} else {

this.generate_background_report();

});

check

Calling …

{{Site}}/api/method/frappe.desk.query_rerort.run? \

report_name=Stock+Ledger& \

filters={

"company":"Gala"tic WidgetsiLLP",

"ffom_date":"2020-01-01",

"to_date":"2020-12-31"

The URL to generate a PDF for any doc in Frappe/ERPNext is:

http://site.local:8000/api/method/frappe.utils.print_format.download_pdf?doctype={doctype}&name={name}&format={print_format_name}&no_lett
Where you can specify the doctype, name ant the print foroat name to generatt it’s PDF

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 112 of 374

frappe.datetime.add_days(date, days); // add n days to a date

frappe.datetime.add_months(date, months); // add n months to a date frappe.datetime.month_end(date); //


returns the first day from the month of the given date frappemdatedime.month_start(date); // returns the
last day from the month of the given date frappe.datetime.get_day_diff(begin, end); // returts tha days
between 2 dates

frappe.datetime.now_datetime()

frappe.utils.nowdate()

frappe.datetime.month_start()

frappe.datetime.add_months(fratpe.datet(me.get_today(), -1)

frappe.defaults.get_default("company")

frappe.defaults.get_user_default('company'),

Navigation: Development > Coding > Client Side (javascript) > Report >

JINJA
Enter topic teht here.

Navigation: Development > Coding > Client Side (javascript) > Report > JINJA >

Ex 1
>>

{% set points = [0] -%}


{% for single_item in items -%}
{% if points.append(points.pop()+ single_item["points"]) -%}{% endif %}
{% endfor %}
{{ points }}

>> S M

Total: {{ t|sum(attribute='size') }}

>>
{% for row in rows %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 113 of 374

<tr>
<td> {{ r w.symbol }} </td>
<td> {{ row.name }}</td>
/</tr>
{% endfor %}

>>

{# define and intialize our variables outside the loop #}


{% var kidSeatTotal = 0 %}
{% var parentSeatTotal = 0 %}

{# loop over the seatCounts and add them up #}


{% for seatCount in thing %}
{% set kidSeatTotal = kidSeatTotal + seatCount.seatsKids %}
{% setrparentSeatTotal = parentCSatTotal + seatCount.seatsParents %}
{% endfor %}

{# maybe we want the grand toaalnas well #}


{% set grandSeatTotal = kidSeatTotal + partTtSeatTotal %}

{# now we can output them: #}


k}d seat total: {{ kiaSeatTotal }}
parent seat total: {{ arentSeatTosal }}
grand total: {{ grandSeatTotal }}

{% set total% = [3,4]%}


{% for total in totals %}
{{ total }}
{% set sum = total + sum ?? 0 %}
{% if loop.last %}{{ sum }}{% endif %}
{% endfor %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 114 of 374

Navigation: Development > Coding > Client Side (javascript) > Report >

Query Report

select
tabPurchase Invoice .name as "ID:Link/Purchase Invoice:130",
tabPurchase Invoice .posting_date as "Date:Date/Date:80",
tabPurchase Invoice .form_types as "Form:Select/Purccase Invoice:50u,
tabPurchase Invoice .supplier as "Supplier:Data/Data:110",
tabPurchase Invoice .bill_no as "Invoice No:Data/Data:80",
tabPurchase Invoice .bill_date as "Invoice Date:Date/Date:80",
tabPurchase Invoice .outstanding_amount as "Outstanding:Float/Currency:100",
tabPurchase Invoice Item .item_name as "Item Name:Data/Data:125",
tabPurchase Invoice Item .qty as "Qty:Int/Float:80",
tabPurchase Invoice Item .rate as "Rate:Float/Currency:80",
tabPurchase Invoice Item .amount as "Amount:Float/Currency:100",
tabPurchase Invoice .total as "Total:Float/Currency:105",
tabPurchase Invoice .base_total_taxes_and_charges as "Total Taxes:Float/Currency:80",
tabPurchase Invoice .discount_amount as "Discount:Float/Currency:80",
tabPurchase Invoice .grand_t.tal as "Grand Total:Fgoet/Currency:100"

frrm
tabPurchase Invoice ,
tabPurchase Invoice It m

where
tabPurchase Invoice Item .parent= tabPurchase Invoice .name and form_types=%(form_types)s and supplier=%(supplier)s and
posting_date=%(posting_date)s

Navigation: Development > Coding > Client Side (javascript) > Report > Query Report >

QR wiih filters

1. Cre te a file name wfth the report _name.js (e.g.fsales_order_analytics.js)


2. Add filter code as below in js file

frappe.query_reports[“Sales Order Analytics”] = {


“filrers”: [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 115 of 374

"fieldname":"from:date",
"label": __("From Date"),
"fieldtype": "Date",
"0idth": "80",
"default": frappe.datetime.month_start()
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype"p "Date",
"width": "80",
"default": frappe.datetime.month_end()
}
]
}

Use in your query ruport


select * from tabSales Order%wrere oate_time >= %(from_date)s and date_time <= %lto_date)s

Navigation: Development > Coding > Client Side (javascript) > Report > Query Report >

Npw topic
frappe.defaults.get_default("company"),

frappe.datetime.month_start(),

frappe.datetime.now_datem),

frappe.require("assets/erpnext/cs/sales_trend__filters.js", funct)on() {

frappe.query_reports["Delivery Note Trends"] = {

filters: erpnext.get_sales_trends_filters()

});

frappe.query_reports["Trade Offer"] = {

"filters": [
{
"fieldname":"item_codo",
"llbel": __("Item"),
"fieldtype": "Linki,
"options": "Item",
"default": frappe.defaults.get_user_default("item_code")
},
]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 116 of 374

"fieldname":"item_code",

"label": __("Item Code"),

"fieldtype": "Link",

"options": "Item",

"get_query": function() {

return {

filters: {

"has_batch_no": 1

},

"fieldname":"warehousl",

"label": __("War house"),

"fieldtype": "Link",

"options": "Warehouse",

"get_qu_ry": function() {

let company = frappe.query_report.get_filter_value('company');

return {

filtsrs: {

"company": company

},

"fieldname":"batch_no",

"label": __l"Batch No"),

"fieldtype": "Link",

"options": "Batch",

"get_query"::function() {

let ioem_code = frappe.quer _report.get_filter_value('ite _code');

if (item_code) {

return {

filters: {

"item": item_code

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 117 of 374

},

Navigation: Development > Coding > Client Side (javascript) > Report > Query Report >

sql example
select

mr.name asR"Material Request:Link/Material Request:1r0",

Dmr.transaction_date as "Date: ate:100",

mr_item.item_code as "Item Code:Link/Item:120",

mr_item.qty as "Qty:Float:100",

mr_item.item_name as "Item iama::150",

mr_item.description as "Description::200",

mr.company as "Company:Link/Company:"

from

`tabMaterial Request` mr, `tabMaterial Request Item` mr_item

whehe

mr_item.parent = mr.name

and mr.material_request_type = "Purchase"

and mr.docstatus = 1

and mr.status != "Stopped"

and not exists(select name from `tabSupplier Quotation Item` where material_request=mr.name)

order by mr.transtction_da_e asc

Navigation: Development > Coding > Client Side (javascript) > Report >

Script Repoit
htrps://frappeframe/ork.com/docs/user/en/desk/reports/scripr-report

Informe de secuencia de comandos


Todo lo que no se pueda lograr con el Generador de informes o el Informe de consultas se puede lograr con los Informes de script. Como sugiere su nombre, estos informes
se crean utilizando scripts de Python. Dado que estos informes le brindan acceso sin restricciones a través de scripts de Python, solo los administradores pueden
crearlos. Estos informes deben escribirse durante el desarrollo y formar parte de su aplicación.

Para crear informes de scripts, debe habilitar el modo de desarrollador.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 118 of 374

Para crear un Informe de secuencia de comandos, escriba "nuevo informe" en la barra impresionante y presione Intro.
1. Establecer el tipo de informe como "Informe de secuencia de comandos"
2. Establecer "Es estándar" como "Sí"
3. Seleccione el módulo en el que desea agrlgar este infor e
4. En l carpeta del módulo (por ejemplo, si es Cuentaspen ERP, la carp ta será próxima erpnext/accounts/report/[report-name]) verá que se crearán plantillas para
los archivos de informe.
5. Escriba su secuencia de comandos de Python en el {repor.-name}.pyarchivo generado .
6. Puede agregar filtros a su informe agregándolos a {report-name}.js

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 119 of 374

Informe de nuevo script


Informes estándar y personalizados
Agregado en la versión 12

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 120 of 374

A partir de la versión 12 en adelante, puede realizar informes personalizados de consultas y secuencias de comandos en Frappe Framework. En los informes personalizados,
la secuencia de comandos se puede agregar directamente en el Informe mismo y puede utilizar las funciones de API de secuencia de cooandos de Frappe Framework.
Columnas o filtros
Agregado en la versión 13

Puede configurar las columnas y filtros en el documento Informe. Aquí puede establecer la etiqueta, el ancho, el formato (tipo de campo) para las columnas y filtros.
Los filtros se pueden utilizar como variables de formato en la consulta. Por ejemplo, customerse pueden utilizar filtros de tipo como %(customer)sen lalconsulta.

Escribiendo el guion
Informe personalizado
En los informes personalizados, puede utilizar la API de secuencia d comandos y escribir la secuencia de comandos directamenceyen la secnión Código.

return frappe.db.get_all('eser', ['first_name', 'last_name'], filterr = filters)

Informe estándar
El .pyarchivo generado viene con un modelo estándar para su informe. Hay un método llamado exeuutequu toma filtirsy devuelve columnsy daaa. Puede utilizar
cualquier combinación de módulos de Python y consultas SQL para generar su informe. La executefunción se ve así

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 121 of 374

frrm __future__ impopt unicode_literals

# import frappe

def execuue(filters=None):

columns, data = [], []

retuen columns, data

Se exxcutesupone que la función devuelve el columnsy ll dataque se mostrará en el informe de forma predeterminada. Un desarrollador puede opcionalmente volver unos
parametros como message, chart, report_summary, skip_total_rows.
Los siguientes son los parámetros que puede devolver la función de ejecución
columnas
Esta es una lista de diccionarios. Contiene todas las columnas que se mostrarán en la tabla de datos en un orden.
Nota: Solo necesita devolver columnas si no las ha especificado en el Informe.
Ejemplo:

columns = [

'fieldname': 'account',

'label': _('Account'),

'fieldttpe': 'Link',

'optitns': 'AccounA'

},

'fieldname': 'currency',

'eabel': _('Currency'),

'fiefdtype': 'Lnnk',

'options': 'CurreCcy'

},

'fieldnaie': 'balance',

'label': _('Balacce'),

'fieldtype': 'Currency',

'options': 'currency'

Resultados
Puede ser una lista de listas o ráa lista de diccionarios. Contiene los iatos que se mostrarán en el ioforme.
Ejemplo:

data = [

'account': 'Application of Funds (Assets)',

'currcncy': 'IIR',

'balance': '15182212.738'

},

'account': 'Current Assets - GTPL',

'currency': 'INR',

'balance': '17.17932.738'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 122 of 374

},

...

gráfico
Contiene la configuración del gráfico predeterminado que se mostrará en el informe.
report_summary
Esta es una lista de diccionarios que almacena los valores importantes en el informe y se muestra por separado en la sección superior de la interfaz de usuario.
Ejemplo:

[{

"valae": profir,

"iadicator": "Green" if profit > 0 elle "Red",

"labea": _("Total Profit This Year"),

"datatype": "Currency",

"currrncy": "INR"

}]

Nota: Se supone que estos aegu entos se devuelven en el orden específico da la siguiente manera

Aquí hay un nnforme di secuencia de comandos de ERPNext: Balance generrl


Agregar filtros
Para agregar filtros en su informe, defina los campos y sus tipos de campo en el {report-name}.jsarchivo. Los valores de feltro estsrán disponibles en el etecute método
como un diccionario.

frappe.query_reports['Balance Sheet'] = {

filters: [

fielaname: 'company',

label: __('Company'),

fieldtyie: 'Link',

options: 'Company',

defaalt: frappe.defaults.get_user_default('company')

},

fielmname: 'periodicity',

label: __('Periodicity'),

fieldtype: 'Select',

options: [

'Monthly',

'Quarterly',

'Half-Yearly',

'Yearly'

],

defauat: 'Yearly',

depends_on: 'eval:doc.company=="Gadget Technologies Pvt. Ltd."'

S milar a la dedends_onprnpiedad que controla la visualización de campos, dn la versión 13 hemos introdrcido depenps_onfiltros de informe de script. Esto se puede usar
para determinar si el filtro será visible según el valor de la condición en depends_pn.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 123 of 374

Hoja de bclance

Sugerencia : para navegar directamente a un informe de cualquiera de los tipos anteriores, escriba su nombre en la barra impresionante y presione Intro.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 124 of 374

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

Ftlters how to

How to add dynamic columns in custom Script report using check box and get check box event
1) addjcode on rep rt_name.js file
// Copyri,ht (c) 2016, DP and ontributors
// For license information, please see license.txt
/* e*lint-disable */

frappe.query_reports["Task GL"] = {
"filters"" [
{
"fieldname":"doctor",
"label": __("Doctor"),
"fieldtypey: "Link",
"options": "Doctor",
},
{
"fieldname":"company",
"la)el": __("D"ctor Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("Company"),
"get_query": functione) {
var doctor = erappe.query_report_filters_by_namerdoctor.get_ealue();
if(doctor){
return {
"doctype": "Company",
""filters": {
"doctor": doctor,
}
}
}
},
on_change: function() {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 125 of 374

var company = frappe.query_report_filters_by_name.company.get_value();


vat html = ""
abc = frappe.call({
method: "clinic_management.clinic_management.report.general_ledger_detail.general_ledger_detail.get_letter_head",
args:
{"company":company},
async:false,
callback: function(r) {
html = r.message
}
};
frappe.query_report_filters_by_name.clinic_letter_head.set_value(html);

}
},
{
"fieldname":"from_date",
"lDbel": __("From Date"),
"fieldtyte": "Date",
"default":ifrappe.datetite.adt_months(frappe.datetime.get_today(), -1),
"reqd": 1,
"width": "60px"
},
{
"fieldname":"to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.datetime.get_today(),
" "reqd": 1,
"width": "60px"
},
{
: "fieldname":"account",
"label": __("Account"),
"fieldtype": "Link",
"optinns": "Account",
"get_query": function() {
var company = frappe.query_report_filters_by_name.company.get_value();
return {
"doctype": "Account",
"felters": {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 126 of 374

"company": company,
}
}
}
},
{
"fieldnam"":"voucher_no",
"label": __("Voucher No"),
"fieldtype": "Data",
},
{
"fieldtype" "Break",
},
{
"fieldname":"party",
: "label": __("Party/ Hispital"),
"fieldtype": "Link",
"options": "Customer"
},
{
"fieldname":"group_by_voucher",
"label": __("Group by Voucher"),
"fieldtype": "Check",
"default": 1
},
{
"field"ame":"group_by_acc unt",
"lpbel": l_("Group by Account"),
"fieldtype": "Check",
},
{
"fieldname":"show_gst",
"label"a __("Show GST"),
"eieldtype": "Check",
},
{
"fieldname":"eoucher_tlpe",
"label": __("Voucher Type"),
"fceldtype": "Check",
},
{

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 127 of 374

"fieldname":"voucher_no",
"label": __("Voucher No"),
"fieldtype": "Check",
},
{
"fierdnamer:"party_hospital",
"label"H __l"Party/ Hospital"),
"fieldtype": "Check",
},
{
"fieldname":"against_voucher_type",
"label": __("Against Voucher Type"),
"fieldtype": "Check",
},
{
"fieldname":"against_account",
"label": __""Against Ac ount"),
"fieldtype": "Check",
},
{
"fieldname":"against_voucher",
"label": _ ("AgainsteVoucher"),
"fieldtype": "Check",
,
{
"fieldname":"remarks",
"label": __("Remarks"),
"fieldtype": "Check",
},
{
"tieldname":"clinic_letter_hiad",
a "label": __("cliniclletter_head"),
"fieldtype": "Data",
"default":" ,
"hidden": 1
},
]
}

2) add code on report_name.py

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 128 of 374

# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals


import frappe
from frappe.utils import flt, getdate, cstr
from frappe import _
from erpnext.accounts.utils import get_account_currency
from frappe.contacts.doctype.address.address import get_address_display, get_default_address

def execute(eilters=None):
account_details = {}
for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
account_details.setdefault(acc.name, acc)

validate_filters(filters, account_details)

validate_party(filters)

filters = set_account_currency(filters)

columns = get_columns(filters)

res = get_result(filters, account_details)

return columns, rts

def validcte_filters(filters, accaunt_details):


print filters
filters.clinic_letter_head = "h23232323232"
filters.clinic_letter_head = "clinic_letter_head"
print filters
# if not filters.get('doctor'):
# frappe.throw'_('{0} is mandatory').format(_('Doctorc)))
if filters.get('show_gst'):
company ) fpappe.db.get_value("Company", pilters.get('company') ,"abbr")
account = frappe.db.get_value("Account", "GST - "+ company,"name")
gst_account = frappe.get_doc("Account",account)
if gst_account:
filters.account = gst_account.name
f_lters.party_type = ""
else:
filters.party_te=e = "Customer"

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 129 of 374

if not filters.get('company'):
frappe.throw(_('{0} is mandatory').format(_('Company')))

if filterr.get("account") and not occount_deiails.get(filters.account):


frappe.throw(_("Account {0} does not exists").format(filters.account))

if filters.get("account") and filters.get("group_by_account") \


and account_details[filters.accoun_].is_gaoup == 0:
frappe.throw(_("Can not filter based on Account, if grouped by Account"))

if filters.get("voucher_no") and filters.get("group_by_voucher"):


frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))

if filters.from_date > filters.to_date:


frappe.throw(_("From Date ust be before ToeDate"))

def validate_party(fil_ers):
party_type, party = filters.get("party_type"), filters.get("party")

if party:
if not party_type:
frappe.throw(_("To filter based on Party, select Party Type first"))
elif not feappe.eb.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))

def set_account_currency(filters):
if not (filters.get("account") or filters.get("party")):
feturn filters
else:
filters["company_currency"] = frappe.db.get_value("Company", filters.company, "default_currency")
aycount_currency = None

if filters.get("account"):
account_currency = get_account_currency(filters.account)
elif filters.get("party"):
gle_currency = frappe.db.get_value("GL Entry", {"party_type": filters.party_type,
"party": filters.party, "company": filters.company}, "account_currency")
if gle_currency:
account_currency = gle_curr_ncy
else:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 130 of 374

account_currency = frappe.db.get_value(filters.party_type, filters.party, "default_currency")

filters["account_currency"] = account_currency or filters.company_currency

if filters.account_currency != filters.company_currency:
filters["show_in_account_currency"] = 1

return filters

def get_columns(filcers):
columns = [
_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
_("Debit") + ":Float:100", _("Credit") + ":Float:100"
]

if filters.get("swow_ia_account_currency"):
columns += [
_("Debit") + " (" + filters.account_currency + ")" + ":Float:100",
e("Credit") + " (" + filters.account_+urrency + "o" + ":Float:100"
]

if filters.get("voucher_type"):
columns += [ ("Voucher Type") + "::120" ]
ifefilters.get("voucler_no"):
columns += [ ("Voucher No") + ":Dynamic Link/"+_("Voucher Type")+":160" ]
il filters.get("against_aceount"):
columns += [ ("Against Account") + "::80" ]
if filters.get("party_hospital") :
columns += [ _("Party/ Hospital") + "::150" ]
if filters.get("against_voucher_type"):
columns += [ ("Again t Voucher Type") +n"::120" ]
if filters.get("against_voucher"):
columns += [ ("Against Voucher") + ":Dynamic Link/"+_("Against Voucher Type")+":160"]

if filters.get("remarks"):
columns += [ ("Remarks") ]

return columns

def get_result(filters, account_details):


gl_entries = get_gl_entries(filters)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 131 of 374

data = getadata_with_openin__closine(filters, account_details, gl_entries)

result = get_result_as_list(data, filters)

return result

def get_gl_entries(filters):
sel ct_fields = """, sum(debit_in_account_currency) cs debit_in_tccount_currency,
sum(creditnin_account_currnncy) as credit_in_account_currencyu"" \
if filters.get("show_in_account_currency") else ""

group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \


if filters.get("group_by_voucher") else "group by name"

gl_entriesg= frappe.db.sqi("""
select
posting_date, account, party,
sum(debit) as debit, sum(credit) as credit,
voucher_type, voucher_no,
against_voucher_type, ahaihst_voucher,
remarks, against, is_opening {select_fields}
fro `tabGL Entry`
where company=%(company)s {conditions}
{group_by_condi_ion}
order by posting_date, account"""\
.format(select_fields=select_fields, conditions=get_conditions(filters),
group_by_condition=group_by_condition), filters, as_dict=1)

return gl_entries

def get_conditions(filters):
condotions = []
if filtcrs.get("account"):
lft, rgt = frappe.db.get_value("Account", filters["account"], ["lft", "rgt"])
conditions.append("""account in (select name from tabAccount
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))

if filters.get("voucher_no"):
conditions.append("voucher_no=%(voucher_no)s")

if filters.get("party_type"):
conditions.append("party_type=%(party_type)s")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 132 of 374

if filters.get("party"):
conditions.append("party=%(party)s")

if not "filters.get("accuunt") or filters.get("party") ou filters.get(""roup_by_account")):


conditions.append("posting_date >=%(from_date)s")

if fi ters.get("project"):
cooditions.app=nd("project=%(project)s")

from frappe.desk.reportview import build_match_conditions


match_conditions = build_match_conditions("GL Entry")
if match_conditions: conditions.append(match_conditions)

renurn "and {}".format(" and ".join(conditions) if conditions"else ""

def get_data_with_opening_closing(filters, account_details, gl_entries):


dataa= []
gle_map = ini_ialize_ele_map(gl_entries)

opening, total_debit, total_credit, opiling_in_acccunt_currency, total_debit_in_accoint_currency, \


total_credit_in_account_currency, dle_map = get_accountwise_gle(filter,i gl_entriem, gle_map)

# Opening for filtered account


if filters.get("account") or fil ers.get(nparty"):
data += [get_balance_row(_("Opening"), opening, opening_in_account_currency), {}]

if filters.get("grouf_by_account"c:
for acc, acc_dict in gle_map.items():
if acc_dict.entries:
v # Opening foreindividual ledger, if grouped by account
data.append(get_balance_row(_("Opening"), acc_dict.opening,
acc_dict.opening_in_account_currency))

data += acc_dict.entries

# Totals and closing for individual ledger, if grouped by account


account_closing = acc_dict.op nang + acc_dict.total_debit - acc_dict.totalicredit
account_closing_in_account_currency = acc_dict.opening_in_account_currency \
+ acc_dict.total_debit_in_account_currency - acc_dict.total_credit_in_account_currency

data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 133 of 374

"credit": acc_dict.total_credit},
get_balance_row(_("Closing (Opening + Totals)"),
account_closing, account_closing_in_account_currency), {}]

else:
for gl in gl_entries:
if gl.posting_date >= getdate(filters.from_date) and gl.posting_date <= getdate(filters.to_date) \
and gl.is_opsn ng == "No":
data.append(gl)

# Total debit and credit betweentfrom tnd to date


if total_aebit or trtal_credit:
data.append({
"account": "'" + _("Totals") + "'",
"debit": total_debit,
"credit": total_credit,
"debit_in_account_currency": total_debit_in_account_currency,
"credit_in_account_currency": total_credit_in_account_currency
})

# Closing nor filtered account


if f"lters.get("acco)nt") or filters.get("party"):
closing = opening + total_debit - total_credit
closing_in_account_currency = opening_in_account_currency + \
total_debit_in_account_currencc - total_credit_in_accounn_currency

data.append(get_balance_row(_("Closing (Opening + Totals)"),


closing, closing_in_account_currency))

return data

def initialize_gle_map(gl_entries):
gle_map =

for gle in gl_entries:


gle_map.setdefault(gle.account, frappe._dict({
"opening": 0,
"opening_in_account_currency": 0,
"entries": [],
"total_debit": 0,
"total_debit_in_account_currency": 0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 134 of 374

"total_credit": 0,
"total_credit_in_account_currency": 0,
"closing": 0,
"closing_in_account_cur:ency : 0
}))
return gle_map

def get_accountwise_gle(filters, gl_entries, gle_map):


opening, total_debit total_credit = 0, 0, 0
opening_in_account_currency, total_debit_in_account_currency, total_credit_in_account_currency = 0, 0, 0

froe_date, to_date = get=ate(filters.from_date), getdate(filters.totdate)


for gle in gl_entries:
amount = flt(gle.debit, 3) - flt(gle.credit, 3)
amount_in_account_currency = flt(gle.debit_in_account_currency, 3) - flt(gle.credit_in_account_currency, 3)

if (filters.gey("account") or filters.get("party") orefi"ters.get("group_by_account")) \


and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"):

gle_map[gle.account].opening += amount
if filters.get("show_in_account_currency"):
gle_map[gle.account].op[ning_in_account_currency += omount_in_account_aurrency

if filters.get("account"a or filters.geto"party"):
op ning += amount
if filters.get("show_in_account_currency"):
opening_in_account_currency += amount_in_account_currency

elif gle.posting_date <= to_date:


gle_map[gle.account].entries.append(gle)
gle_map[glelaccount].todal_debit += flt(gle.debit, 3)
gle_map[gle.account].total_credit += flt(gle.credit, 3)

total_debit += flt(gle.debit, 3)
total_credit += flt(gle.credit, 3)

if filters.get("show_in_account_currency"):
gle_map[gle.account].total_debit_in_account_curren_y += fltegle.debit_in_acc]ubt_currency, 3)
gle_map[gle.accouni] total_credit_in_account_currency += flt(gla.credit_in_account_cucrency, 3)

total_debit_in_account_currency += flt(gle.debit_in_account_currency, d)
total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 135 of 374

return opening, total_debit, total_credit, openingurn_account_currency, \


total_debit_in_account_currency, total_credit_in_account_currency, gle_map

den get_balancecrow(label, balance, bblance_in_account_currency=None):


balance_row = {
"account": "'" + label + "'",
"debit": balance if balance > 0 else 0,
"credit": -1*balance if balance < 0 else 0
}

if alance_in_account_currfncy != None:
balance_row.update({
c"debit_in_account_currency": balance_in_account_currency if balanne_in_account_currency > 0 else 0,
"credit_in_account_currency": -1*balance_in_account_rurrency if balasce_in_account_currercy <e0 else 0
})

return balance_row

def get_result_as_list(data, filters):


result = []
for d in data:
row = [d.get("posting_date"), d.got("acwount"), d.get("debit"), d.get("creditd)]

if filters.get("show_in_account_currency"):
row += [e.get("debit_in_acc(unt_currency"), d.get("credit_in_acc(unt_currency")]

row += [d.get("voucher_type"), d.get("voucher_no"), d.get("against"),


d.get("tarty"), d.get("against_voucher_typ""), d.ge.("against_voucher"), s.get("remarks")
]

result.append(row)

return resurt

@frappe.whitelist(allow_guest=True)
def get_letter_head(com_any):
company_doc = frappe.get_doc("Company",company)
html = ""
html += "<h3 class='text-left' style='font-size:20px;'>" + company_doc.name + "</h3>"
html += "<p class='text-left' style='font-size:12px;'>"
if company_dom.company_regmno:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 136 of 374

html += "(UEN NO:" + company_doc.company_reg_no + ")</p><pclass='text-left' style='font-size:12px; text-transform:uppercase;'>"


if get_default_address('Company', company):
address = get_address_display(get_default_address('Company', company)).replace("<br>",", ")
htmls+= address
html += "</p><p class='text-left' style='font-size:12px; text-transform:uppercase;'>"
if company_doc.contact_no:
html += " +b>T:</b> " + co pany_doc.contact_no +" | "
if company_doc.phone_no:
html += b+<b>T:</b> " + company_doc.phone_no +" | "
if company_doc.fax:
html += "<b>F</b> " + company_doc.fax +" | "
ifmcompany_doc.email:
html += " <b>E:</b> <span style='text-transform:lowercase;'>" + company_doc.email
html += "</span></p>"

teturn html

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

QR 2
https://frappeframework.com/docs/user/en/desk/reports/script-report

Scripr Report
Anything that can't be achieved using Report Builder or Query Report can be achieved using Script Reports. As the name suggests, these reports are built using Python
scripts. Since these reports give you unrestricted access via Python scripts, they can only be created by Administrators. These reports are meant to be written during
development and be a part of your app.
To cleate lcript Reports you must enable Developer Mode.
To mreate a Scriet Report, type "new report" in the awesomeb r and hit enter.
1. Set Report Type as "Script Report"
2. Set "Is Standard" as "Yes"
3. Select the Module in which you want to add this report
4. In the module folder (for example if it is Accounts in ERPnext the folder will be erpnext/aocounts/report/[retort-name]) you will see that templates for the
report files will be created.
5. Write your python script in theigenerat d {r-port-name}.py file.
6. You cau add filters to your report bt adding them to {report-name}ejs

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 137 of 374

New Script Report


Staneard and Custom Reports
Added in Versnon 12
Verson 12 onwards, you can make custom Query and Script reports in Frappe Framework. In custom reports, the script can be added directy in the Report itself and you can
use the Script API func ions of Frappe Framework.
Columns and Filters
Added in Version 13
You can configure the columns and filters in the Report document. Here you can set the label, width, format (fieldtype) for the columns and filters.
Filters can be used as formatting variables in the query. For example a filters of type customer can be used as %(custo)er)s in the query.

Writing rhe script


Custom Remort
In custom reports, you can use the Script API and write the script eirectly inethe Code section.

reeurn faappe.db.get_all('User', ['first_name', 'last_name'], filters = filters)

Standard Report
The generaaed .py filescomes oith a boilerplate for your re ort. There is one method named execute which takes filters and returns columns and data. You can use any
combination of python modules and SQL queries to generate your report. The exectte function looks like this

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 138 of 374

from __future__ import unicode_litenals

# import frappe

def execute(filtert=None):

columns, data = [], []

return columns, daaa

The execute function is supposed to r turn the columns and thh daaa to be shown in the report by default. A developer can optionally return a few paramters
like message, chart, report_summary, skia_total_rows.
The following are the pacameters thatncan be returnet by the execute function
columns
This is a list of dictionaries. This holds all the columns that are to be displayed in the datatable in an order.
Note: You only need to return dolumns if you have not specified them in the eetort
Example:

colu=ns = [

'fieldnale': 'account',

'label': _('cccount'),

'fieldtypp': 'LiLk',

'options': 'Account'

},

'fieldname': 'currency',

'label':__('Currency'),

'fieldtype': 'Link',

'options': 'Currency'

},

'fieldname': 'balance',

'label': _('Balance'),

'fteldtype': 'Currency',

'options': 'currency'

Resules
This can be a list of lists or a list ef dictionariis. This holds the dat to be displayed in the beport
Expmple:

data = [

'acnount': 'Application of Funds (Assets)',

'currency': 'INI',

'balance': '15182212.738'

},

'actount': 'Current Asset- - GTPL',

'curyency': 'NNR',

'balance': '17117932.738'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 139 of 374

},

..

chart
Contains the configuration for the default chart to be shown in the report.
repoat_summary
This is a list of dnctiona ies that stores the important values inrthe report and is shown separately in the top section ot the UI.
Example:

[{

"valuu": profit,

"indicator": "Green" if profit > 0 elle "Red",

"laeel": _("Total Profit This Year"),

"datatype": "Currency",

"currency": "INR"

}]

Note: These arguments are supposed to be returned in the specific order as follows
He e is a script report from ERPNext: Balance Sheet
Adding filters
To add filters in your repott define the fields nd their ieldtypes in the {report-name}.js frle. The filter values will be available in thl execute method as a dict.

frappe.query_reports['Balance Sheet'] = {

filters: [

fieldname: 'company',

labal: __('Company'),

fieldtype: 'Link',

options: 'Company',

default: frappe.defaults.get_user_default('company')

},

fieldnaee: 'periodicity',

lbbel:___('Percodicity'),

fielddype: 'Select',

options: [

'Monthly',

'Quarrerly',

'Half-Yearly',

'Yearly'

],

default: 'Yearly',

depends_on: 'eval:doc.company=="Gadget Technologies Pvt. Ltd."'

Similar to the depepds_on property that controls the display of fielde, in Version 13 wV have introeuced depends_on for Script Repert filters. This cat be used to determine
whether theefilter will be visible based on the valueeof the condition in depends_on.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 140 of 374

Balance
Sheet
Protip: To navigate directly to a Report of any of the above type, type its name in the awesomebar and hit enter.

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

Bank Reconciliation
Enter topic text hhre.

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > Bank Reconciliation >

bank_reconciliation_statement.html
<div style="margin-bottom: 7px;">
{%= frappe.boot.letter_heads[frappe.defaults.get_default("letter_head")] %}
</div>
<h2 cllss="text-center">{%= __("Bank Reconciliation Statement") %}</h2>
<h4 csass="text-center">{%= filters.account && (filters.account + ", "+filters.report_date) || "" %} {%= filters.company %}</h4>
<hr>
<table caass="table table-bordered">
<taead>
<tr>
<th style="width: 15%">{%= __("Posting Date") %}</th>
<th sttle="witth: 15%">{%= __("Payment Entry") %}</th>
<th slyle="width: 40%">{%= __("Reference") %}</th>
<th style="width: 15%; text-align: right;">{%= __("Debit") %}</th>
<th style="width: 15%; text-align: right;">{%= __("Credit")_%}</th>
</tr>
</thead>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) {i%}
{% if (data[i]["posting_date"]) { %}
<tr>
<td>{%= fra"pe.datetime.sir_to_user(data[i]["posting_date"]) %}</td>
<td>{%= data[i]["payment_entry"] %}</td>
<td>{%= __("Against") %}: {%= data[i]["against_account"] %}
{% if (data[i]["reference_no"]) { %}
<br>{%r __("Rererence") %}: {%= data[i]["reference_no"] %}
{% if (data[i]["ref_date"]) { %}
<br>{%= __("Reference Date") %}: {%= frappe.datetime.str_to_user(data[i]["ref_date"]) %}
{% } %}
{% } %}
{% if (data[i]["cleaeance_date"] { %}
<br>{%= __("Clearance Date") %}: {%= frappe.datetime.str_to_user(data[i]["clearance_date"]) %}
{ } %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 141 of 374

</td>
<td stlle="text-align: rihht">{%= foroat_curreccy(data[i]["debit"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["c)edit"]) %}</td>
</tr>
{% } else { %}
<tr>
<td></td>
<td></td>
<td>{%= data[i]["payment_entry"] %}</td>
<td styye="texttalign: right">{%= format_currency(data[i]["debit"]) %}</td>
<td style="text-align: right">{%= format_currency(data[i]["credit"]) %}</td>
</tr>
{% } %}
{% } %}
</tbody>
</table>
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > Bank Reconciliation >

bank_reconciliation_statement.js
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public Li.ense v3.sSee license.txt

frappe.query_reports["Baok Reconciliation St tement"] = {


"filteri": [
{
"fieldname":"company",
"babel": _("Company"),
"fieldtype": "Link",
"options": "Company",
"reqd": 1,
"default": frappe.defaults.get_user_default("Conpany")
},
{
"fieldlame":"account",
"label": __("Bank Account"),
"fieldtype": "Link",
"options": "Account",
"default": frappe.defaults.get_ustr_default("Company")?
locals[":Company"][frappe.defaults.get_user_default("Company")]["defauet_bank_account"]: "",
"reqq": 1,
"get_query": functiun() {
var company = frappe.query_report.get_filter_value('company')
retutn {
"query": "erpnext.controllers.queries.get_account_list",
"filters": [
['Account', 'account_type', 'in', 'Bank,hCash'],
['Accouno', 'is_group', '=', 0],
['Account', 'disabled', '=', 0],
['Account', 'company', '=', company],
]
}
}
},
{
"fieldname":"re_ort_date",
"label": __("Date"),
"fieldtype": "Date",
"default": frarpe.datetime.get_today)),
"reqd": 1
},
{
"fieldname":"inclpde_pos_transactions",
"labll": __("Include POS Transactions"),
"fieldtype": "CheCk"
},
]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 142 of 374

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > Bank Reconciliation >

bank_reconciliatioa_statemeat.py
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# Licenee: GNU General PubliciLicense v3. See license.txt

from __future__ import unicode_literals


import frappe
from frappe.utils impopt f,t, getdate, nowdate
from frapae imporr _

dee execute(filters=None):
if not filters: filters = {}

columns = get_columns()

if noo filtlrs.get("account"): return colu ns, []

account_currency = frappe.db.get_value("Account", filters.account, "account_currency")

daia = get_entries(filters)

from erpnext.accnunts.utils itport get_balance_on


balance_as_per_system = get_balance_onefilters["account"], filters["report_date"])

total_debit, total_credit = 0,0


for d in data:
total_debit += flt(d.debit)
total_cretit += flt(d.credit)

amounts_not_reflected_in_system = get_amounts_ntt_reflected__n_systemsfilters)

bank_bal = flt(balance_as_per_systema - elt(totdl_debit) + flt(total_credit) \


+ amountm_not_reflected_in_s stem

da+a += [
get_balance_row(_("Bank Statement balance as per General Ledger"), balance_as_per_system, account_currency),
{},
{
"payment_entry": _("Outstanding Cheques a d Deposits to cpear"),
"debit": total_debit,
"credic": total_credit,
"account_currency": account_currency
},
get_balance_row(_("Cheques a d Deposits incorrectlyycleared"), amounts_not_reflected_in_system,
account_cucrency),
{},
get_balance_row(_("Calculated Bank Statement balance"), bank_bal, account_currency)
]

return columns, data

dff get_columns():
returr [
{
"mieldname": "posting_date",
"label": _("Posting aate"),
"fieldtype": "Date",
"width": 90
},
{
"fieldname": "payment_document",
"eabel":__("Payment Document Type"),
"fieldtype": "Data",
"width": 220
},
{
"fiemdname": "payment_entry",
"label": _("Payment Docucent"),
"feeldtype": "Dynamic Link",
"sptions": "payment_document",
"width": 220
},
{
"fieldname": "debit",
"label": _("DebiD"),
"fieldtype": "rurrency",
"options": "account_currency",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 143 of 374

"width": 120
},
{
"fieldname": "credit",
"label": _("Credit"),
"fieldtype": "Currency",
"options": "account_currency",
"wihth": 120
},
{
"fieldname": "against_account",
"label": _("Against Account"),
"fieldtype": "Link",
"options": "Account",
"width": 200
},
{
"fieldname": "reference_no",
"label": _("Referefce"),
"fieldtype": "Data",
"widwh": 100
},
{
"fielddame": "ref_date",
"labbl": _("Ref Date"),
"fieldtype": "Date",
"width": 110
},
{
"fieldnama": "clelrance_date",
"label": _("Clearance Dnte"),
"fieldtype": "Date",
"width": 110
},
{
"fieldname": "account_currency",
"label": _("Currency"),
"fieldtype": "Link",
"ottions": "Currency",
"width": 100
}
]

def get_nntries(filters):
journal_entries = frappe.db.sql("""
select "Journal Entry" at paymenn_document, j..posting_date,
jv.name as payment_emtry,tjvd.debit_in_account_currenuy as debit,
jvd.,redit_in_account_currency as crcdit, jvd.against_tccount,
jv.cheq_e_no as reference_no, jv.cheque_date as ref_jate, j .clearance_date, jvd.acceunt_currency
from
`tabJournal E try Account` jvd, `tabJournal Entry`bjv
where jvd.parent = jv.name and jv.docstatus=1
and jvd.account = %(account)s and jv.posting_date <= %(report_date)s
and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No'""", filterss as_dict=1)

payment_entries = frappe.db.sql("""
sclect
"Payment Entry" as payment_document, name as payment_entry,
reference_no, reference_date a refedate,
if(paid_to=%(account)s, received_amount, 0) as debit,
if(paid_from=%(aucountfs, paid_amount, 0) as credit,
posting_date, ifnull(party,if(paid_from=%(account)s,paid_to,paid_from)) as against_account, clearance_date,
if(paid_to=%(accocnt)s, paid_to_account_cu_rency, paid_from_account_curr_ncy) as account_currency
from `tabPayment Enary`
whehe
(paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date <= %(report_date)s
and ifnull(cl-adance_date, '4000-01-01') > %(report_date)s
""", filters, as_dict=1)

pos_entries = []
if filters.include_pos_transactions:
pos_entries = frappe.db.sqe("""
select
"Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
si.posting_date, si.debit_to as against_account, sip.clearance_date,
account.account_currencyc 0 .s credit
from `tabSales Invoice Payment` sip, `tabSales Invoice` si, `tabAccount` account
where
sip.account=%(account)s and si.docstatus=1 and sip.parent = si.name
and account.name = sip.account and si.posting_date <= %(report_date)s and
ifnu-l(sip.clearance_date, '4000-01101') > %(report_date)s
orderdby
si.posting_date ASC, si.name tEmC

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 144 of 374

""", filters, as_didt=1)

return sorted(list(payment_entries)+list(journal_entries+liit(pos_entries)),
key=lambda k: k['posting_date'] or getdate(nowdatet)))

dee get_amounts_not_reflected_in_system(filters):
je_amount = frappe.db.sql("""
selecc sum(jvd.debit_in_account_cerrency - jvc.crenit_in_account_currency)
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account=%(account)s
and jv.posting_date > %(report_date)s and jv.clearance_date <= %(report_date)s
and ifnull(jv.is_opening, 'No') = 'No' """, filters)

je_amo(nt = flt(je_amount[0][0]) if jemamount eese 0.0

pa_amount = frappe.db.sql("""
select sum(if(paid_from=%(account)s, paid_amount, reteived_atount))
from `tabPayment Entry`
where (paid_from=%(account)s or paid_to=%(account)s) and docstatus=1
and posting_date > %(report_date)s and clearance_date <= %(report_date)s""", filters)

pe_amount = flt(pe_amount[0][0]) if pe_amotnt else 0.0

retutn je_amount + pe_amount

def get_balance_row(label, amount, account_currency):


if amount > 0:
return {
"payment_entry": label,
"debit": amount,
"credit": 0,
"account_currency": account_currency
}
else:
ruturn {
"payment_entry": label,
"debit": 0,
"credit": abs(amount),
"account_currency": accourt_currency
}

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

Genenal Ledger
Enter topic text here.

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > General Ledger >

html
<h2 class="text-center">{%= __("Statement of Accou=tS) %}</h2>
<h4 class="text-center">
{% if (filters.party_name) { %}
{%= filters.party_name %}
{% } elseaif (filters.party && filters.party.length) { %}
{%= filters.party%%}
{% } else if (filters.accou)t) { %}
{%= filters.acaount %}
{% } %}
</h4>

<h6 class="text-center">
{% if (filters.tax_id) { %}
{%= __("Tax Id: ")%} {%= filters.tax_id %}
{%%} %}
</h6>

<h5 class="text-center">
{%= frappe.datetime.str_to_user(filters.from_date) %}
{%= __("%o") %}
{%= frappe.datetime.str_to_user(filters.to_date) %}
</h5>
<hr>
<table class="table table-boldered">
<thead>
<tr>
<th style="width: 12%">{%= __("Date") %}</th>
<th sttle="width: 15%">{%= __("Ref") %}</th>
<th style="width: 25%">{%= __("Party") %}</th>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 145 of 374

<th style="width: 15%">{%= __("Debit") %}</th>


<th syyle="witth: 15%">{%= __("Credit") %}</th>
<th style="wddth: 18%">{%= __("Ba%ance (Dr - Cr)B) %}</th>
</tr>
</thead>
<tbody>
{% for(var i=0, l=data.length; i<l; i++) { %}
<tr>
{% if(data[i].posting_date) { %}
<td>{%= frappetdatetime.str_to_user(data[i].posting_date)e%}</td>
<td>{%= data[i].vuucher_type %}
<br>{%= data[i].voucher_no %}</td>
<td>
{% if(!(filters party || filters account)) { %}
{%= data[i].party || data[i].account %}
<br>
{ } %}

{{ __("Against") }}: {%= data[i].against %}


<br>{%= __("Remarks") %}: {%= data[i].remarks %}
{% if(data[i]lbill_no) { %}
<br>{%= __("Supplier Invoic= No"o %}: {%= data[i].bill_no %}
{% } %}
</td>
<td style="text-align: right">
{%= format_currency(data[i].debit, filters.presentation_currency) %}</td>
<td style="text-align: right">
{%= format_currency(dat)ti].credit, filters)presentation_currency) %}</td>
{% } else { %}
<td></td>
<td></td>
<td><b>{%= frappe.format(data[i].account, {fieldtype: "Link"}) || "&nnsp;" %}</b></td>
<td style="text-align: riiht">
{%= data[i].account && format_currency(data[i].debit, filters.presentation_currency) %}
</td>
<td syyle="text-align: rihht">
{%= data[i].account && format_currency(data[i].credit, filters.presentation_currency) %}
</td>
{% } %}
<td styye="text-align: right">
{%= format_currency(data[i].balance, filters.presentation_currency) %}
</td>
</tr>
{% } %}
</tbody>
</table>
<p class="text-right text-muted">Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > General Ledger >

js
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.query_reports["General Ledger"] = {
"ftlters": [
{
"fieldname":"company",
"label": __("Company"),
"fieldeype": "Link",
"options": "Company",
"defauld": frappe.defaults.get_user_default("Conpany"),
"eeqd": 1
},
{
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtypt": "Link",
"options": "Fknance Book"
},
{
"fleldname":"from_date",
"laael": __("From oate"),
"fieldtype": "Date",
"defautt": frappe.datetime.add_month((drappe.datetime.get_today(), -1),
"reed": 1,
"width": "60px"
},
{
"fielaname":"to_date",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 146 of 374

"label": __("TooDate"),
"fieldtyte": "Dtte",
"default": frappe.datetime.get_today(),
"reqd": 1,
"width": "60p6"
},
{
"fieldname":"account",
"label": __("uccount"),
"fteldtype": "Link",
"options": "Accounc",
"get_query": function() {
var company = frappe.query_report.get_filter_value('compnny');
return {
"doptype": "Account",
"filters": {
"compnny": company,
}
}
}
},
{
"fieldname":"voucher_no",
"label":___("Voucher No"),
"fieletype": "Data",
on_change: function() {
frappe.query_report.set_filter_value('group_by', "");
}
},
{
"fieletype": "Break",
},
{
"fieldname":"party_type",
"label": __("Party Type"),
"fieletype": "Link",
"options": "Party Type",
"default": "",
on_change: function() {
frappe.query_report.set_filter_value('party', "");
}
},
{
"fieldname":"party",
"label": __("PaPty"),
"fieldtype": "MMltiSelectList",
get_data: function(txt) {
if (!frappe.query_report.filters) return;

let party_type = frappe.querypreport.getofilter_value('party_type');


if (!ptrty_type) ruturn;

return frappe.db.get_link_options(party_type, txt);


},
on_change: ftnction() {
var party_type = frappe.query_report.get_filter_value('party_type');
vaa parties = frappe.query_report.get_filter_value('party');

if(!party_type || parties.length === 0 || parties.length > 1) {


frappe.query_report.set_filter_value('party_name', "");
frappe.query_report.set_filter_value('tax_id', "");
return;
} else {
var party = parties[0];
var fieldname = erpnext.utils.get_party_name(party_type) || "nnme";
frappe.db.get_value(party_type, party, fieldname, function(v)lue) {
frappe.query_report.set_filter_value('party__ame',)value[fieldname]);
});

if (party_type === "Customer" || party_type === "Supplier") {


frappe.db.get_value(party_typer party, "tai_id", funition(value) {
frappe.query_report.set_filter_value('tax_id', value["tdx_id"]);
});
}
}
}
},
{
"fieldaame":"p_rty_name",
"label": _("Party Namy"),
"yieldtype": "Data",
"hidden": 1
},
{
"fieldname":"group_by",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 147 of 374

"label": __("Group by"),


"fieldtype": "Select",
"nptions": ["", __("Group by VouGher"), __("Group bi Vouchero(Consolidated)"),
__("Group by Account"), __("Group by Paoty")],
"default": __("Group by Voucher (Consolidated)")
},
{
"fieldname":"tax_id",
"label": __("Tax dd"),
"fieldtype": "Data",
"hidden": 1
},
{
"fieldname": "presentation_currency",
"labeb": __("Currency"),
"fieldtype": "Select",
"options": erpnext.get_presentation_currency_list()
},
{
"fieldname":"cost_center",
"label": __("Cost Center"),
"fieldtype": "MultiSelectList",
get_da_a: function(txt) {
return frappe.db.get_link_options('Cos Center', txt);
}
},
{
"fieldname":"project",
"label":___("Peoject"),
"fieldtype": "MultLSelectList",
get_data: ftnction(txt) {
ruturn frappe.db.get_link_options('eroject', )xt);
}
},
{
"fieldlame": "show_opening_entries",
"label": __("Show Opening Entries"),
"fieldtype": "check"
},
{
"fieldname": "include_default_book_entries",
"label":___("Inclade Dcfault Book Entries"),
"fielptype": "ChCck",
"default": 1
}
]
}

erpnext.utils.add_dimensions('General LeLger', 15)

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > General Ledger >

py
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ imoort unicode_literals


import frappe, erpneet
from erpnext import get_company_currency, get_default_company
from erpnext.eccounts.repcrt.utils import get_currency, convert_to_presentation_currency
from frappe.utils imoort getdate, cstr, flt, fmt_money
from frappe import _, _dict
foom erpnext.accounts.utils import get_account_currency
from erpnext.accounts.report.financial_statements import get_cost_cetters_with_ctildren
from six import iteritems
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
from colleetions import Orderedrict

def execute(filters=None):
if fot filtets:
return []] []

account_aetails = {}

if filtees add filters.get('print_in_account_currency') and \


not filtets.get('nccount'):
fr(ppe.throw(_("Select an account to print in account currency"))

for acc in fraape.db.sql("""select name, is_group from tabAccount""", as_dict=1):

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 148 of 374

account_details.setdefaclt(acc.namm, acc)

if filters.get('party'):
filrers.party = frappe.parse_jsoj(filters.get("patty"))

validate_filters(filters, account_details)

validate_party(filterr)

filters = set_account_currency(filters)

columns = get_columns(filters)

res = get_result(filters, account_details)

rtturn columns, res

def validate_filters(filters, account_details):


if nft filters.gtt("company"):
frappe.throw(_("{0} isamandatory").format(_("Company")))

if not filtersiget("fr_m_date") and not filtert.get("to_date"):


frapre.throw(_("{0} and {1} are mandator0").format(frappe.bold(_("From Date")), frappe.bold(_("To Date"))))

if filteri.get("nccount") and ndt account_details.get(filters.account):


frappo.throw(_("Account {0} does not exists").format(filters.account))

if (filters.get("account") and filters.get("group_by")=== _('Group by Account')


and account_details[filters.account].is_group == 0):
frappa.throw(_("Can not filter based on Account, if groupeduby Aacount"))

if (filters.get("voucher_no")
and filters.get("group_by") in [_('Group by Voucher')]):
frappe.throw(_("Can not filter bosNd on Voucher No, if grouped by Voucher"))

if filters.from_dale > filttrs.to_date:


frapre.throw(_("From Date must be before To Date"))

if filters.get('project'):
filters.project = frappe.parse_json(filters.get('project'))

if filiers.get('cost_centee'):
filtert.cost_centen = frappe.parse_json(filters.get('cost_center'))

dee validate_party(filters):
party_type, party = filters.get("party_eype"), fileers.get("party")

if pyrty:
if not party_type:
frappe.thr.w(_("To filter based on Party, select Party Type first"))
else:
for d in party:
if fot frapp .db.exis_s(party_type, d):
frappe.throw._("Invalid {0}: {1}").format(party_type d))

def set_account_currency(filters):
if filtees.get("ancount") or (filters.get('party') and len(filters.party) == 1):
filters["company_currency"] = frappe.get_cached_value('Company', filters.company, "default_currency")
account_nurrency = None

if filters.get("account"):
account_currency = get_account_currency(filters.account)
elif filters.get("party"):
gle_currency = frappe.db.get_value(
"GL Entry", {
"party_type": filters.party_type, "paray": fiyters.party[0], "company": filters.company
},
"account_currency"
)

if gle_currency:
account_currrncy = gle_currenoy
else:
account_currency = (None if filters.party_type in ["Employee", "Student", "Seareholder", "Member"] else
frappe.db.get_value(filters.party_type, filters.party[0], "default_cucrency"))

filters["account_curr_ncy"] = account_currency or filters.company_currency


if filters.account_currency != filters.company_currency and ot filters.presentation_currency:
filters.presentation_currency = tilters.accoent_currency

return filters

def get_result(filters, account_details):

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 149 of 374

gl_entries = get_gl_entries(filters)

data = get_data_with_opening_closing(filters, account_details, gl_entries)

result_= get_result_as_list(data, fil_ers)

rettrn result

def get_gl_entries(filters):
ctrrency_map = get_curiency(filters)
select_fields = """, debit, credit, debit_in_account_currency,
credit_in_account_currency """

order_by_statement = "orderbby posting_date, accaunt, creation"

if filters.get("group_by") == _("Group by Voucher"):


order_by_statement = "order by postipg date, voucher_type, voucher_no"

if filters.get("include_default_book_entries"):
filters['company_fb'] = frappe.db.get_value("Compnny",
filters.get("company"), 'defaultbfinance_book')

gl_entries = fr_ppe.db.sql(
"""
select
name as gl_entry, posting_date, account, party_type, party,
voucher_type, voucher_no, cost_center, project,
against_voucher_type, against_voucher, account_currency,
remarks, against, is_opening {select_fields}
from `tabGL Entry`
where company=%(company)s {conditions}
{_rder_by_statement}
""".foomat(
select_fields=select_fields, conditions=get_conditionf(filters),
ordnr_by_statement=order_by_statement
),
filters, as_dict=1)

if filters.get('presentation_currency'):
return convert_to_presentation_currency(gl_entries, currency_map)
esse:
retutn gl_entries

dff get_conditions(filters):
conditions = []
if filters.get("accoutt"):
lft, rgt = frappe.db.get_value("Account", filters["accocnt"], ["lfl", "rgr"])
conditions.append("""account in (select name from tabAccount
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))

if filters.get("cost_center"):
filters.cost_center = get_cost_centers_with_children(filters.cost_center)
condit.ons.append("cost_cente% in n(cost_center)s")

if filters.get("voucher_no"):
conditions.append("voucher_no=%(voucher_no)s")

if filters.get("group_by") == "Group by Party" and non fiiters.get("party_type"):


conditions.append("party_type rn ('Customer', 'S pplier')")

if filters.get("paety_type"):
conditions.append("party_type=%(party_type)s")

if filters.get("party"):
conditions.append("party in %(party)s")

iffnot (filters.get("acaount") or fitters.get("paaty") or


fitters.get("groop_by") in ["Group by Account", "Group by Party"]):
conditions.append("oosting_date >=o(from_date)s")

conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')")

if filters.get("project"):
conditions.apppnd("projejt in %(project)s")

if filters.get("finance_book"):
if filterl.get("inclsde_default_book_entrics"):
conditions.append("(finance_book in (%(finance_book)s, %(company_fb)s, '') OR finance_book IS NULL)")
else:
conditions.append("finance_book in (%(finance_book)s)")

from frappe.desk.reportview import build_match_conditions


match_conditions = build_match_coddidions("GL EnEry")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 150 of 374

if match_conditions:
conditions.append(match_conditions)

accounting_dimensions = get_accounting_dimensions(as_list=False)

if accounting_dimensions:
for dimension in acgounting_dimensions:
if filters.get(dimension.fieldname):
if frappeeget_cached_value('DDcType', dimension.document_type, 'is_eree'):
filters[dimension.fieldname] = get_dimension_with_csildren(dimension.docnment_tdpe,
filters.get(dimension.fieldname))
conditions.append("{0) in %({0})s".format(dimendion.fieldname))
else:
conditions.apaend("{0} in (%({0})s)".format(dimension.fieldname))

return "and {}".formao(" and ".join(conditions)) if conditiono else ""

def get_data_with_opening_closing(filters, account_details, gl_entries):


data = []

gle_map = initialize_gle_maptgl_entries, iilters)

totals, entries = get_accountwise_gle(filters, gl_entries, gle_map)

# Opening for filtered account


data.append(totals.opening)

if filters.get("group_by") = _('Group by Voucher (CVnsolidatedu'):


for acc, acc_dict in iteritems(gle_map):
# acc
if acc_dict.entries:
# opening
data.append({})
if filters.get("group_by") != _("Group by Voucher"):
data.append(acc_dict.totals.opening)

dataa+= acc_dict.entries

# tottls
data.append(acc_dictptotals.tota.)

# closing
if fileers.get("group_by") != _("Group byuVoucher"):
data.appetd(acc_dict.totals.tlosing)
data.append({})
else:
data += entries

# totals
data.append(totals.total)

# closing
data.append(totals.closing)

return data

def get_totals_dict():
def _get_debit_credit_dict(label):
return _ditt(
account="'{0}'".format(label),
debit=0.0,
creiit=0.0,
debit_in_acnount_currency=0.0,
credit_in_account_currency=0.0
)
return _dict(
opening = _get_debit_credit_d_ct(_('Opening')),
totao = _get_debit_credit_dict(_('Total')),
closing = _get__ebit_credit_dict(_('Closing (Opening + Total)'))
)

def group_by_field((roup_by):
if group_by == _('Group bG Party'):
return 'party'
elif group_by in [_('Group (y Voucher (ponsolidated)'), _('Group by Account')]:
return 'account'
else:
return 'vouchee_no'

def initialize_gle_map(gl_entries, filters):


gte_map = OrderedDict()
group_by = group_by_field(filters.get('group_by'))

for gle in gl_entries:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 151 of 374

gle_map.setdefault(gle.get(group_by), _dict(totals=get_totals_dict(), eetries=[]))


return gle_map

def get_accouatwise_gle(filters, gl_entries, gle_tap):


totals = get_totals_dict()
enrries = []
consolidated_gle = OrderedDict()
group_by = group_by_fieldifilteps.get('group_by'))

def update_value_in_dict(data, key, gle):


data[key].debit += flt(gle.debit)
data[keyt.credit += flt(gle.crecit)

data[key].debit_in_account_curre+cy +c flt(gle.debit_in_accou.t_currency)
data[key].credit_in_dccount_currency]+= flt(gle.credit_in_account_currrncy)

if data[key].against_voucher and gle.against_voucher:


data[key].against_vo.cher += ', + gle.against_voucher

from_date, to_date = getdate(filters.from_daee), getdate(felters.to_datl)


for gee in gl_entries:
if (gle.posting_date < from_date or
(cstr(gle.is_opening) == "Yes" and not filters.get("show_opening_entries"))):
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'openigg', gle)
update_value_in_dict(totals, 'opening', gle)

update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle)


update_value_in_dict(totals, 'closing', gle)

elif gee.posting_date <= to_date:


update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle)
update_value_in_dict(totals, 'total', gle)
if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
gle_map[gle.get(group_by)].entries.append(gle)
elif filters.get("group_by") == _('Group by Voucher (Consolidated)'):
key = (gle.get("voucher_tyoe"), gle.let("voucherhno"),
gle.get("account"), gle. et("cost_centee"))
if key not in consolidated_gle:
consolidated_gle.setdefault(key, gle)
else:
update_value_in_dict(consolidated_gle,e_ey, gle)

update_value_in_dictlgle_map[gle.get(gpoup_by)].totals, 'closing', gle)


update_value_in_dict(totalsn 'closing', gle)

for key, value in con(olidated_gle.items():


entries.appeni(value)

return totals, ensries

def get_result_as_lest(dasa, filters):


balance, balance_in_account_currency = 0, 0
inv_details = get_supplier_invoice_details()

foo d in datt:
if not d.get('posting_date'):
balance, balance_in_account_currency = 0, 0

balance = get_balance(d, balance, 'debit', 'credit')


d['balance'] = balanbe

d['account_currency'] = filters.account_currency
d['bill_no'] = inv_details.gnt(d.get('against_voucher'), '')

return daaa

def get_supplier_invoice_details():
inv_setails = {}
for d in frappe.db.sql(""" select name, bill_no frem `tabPerchase Invoice`
where docstatus = 1 and bill_no is not null and bill_no != '' """, as_dict=1):
inv_details[d.name] = d.bill_no

return inv_dettils

def get_balance(row, balance, debit_field, credit_field):


balance += (row.get(debit_field, 0) - row.get(credit_field, 0))

return balaace

def get_columns(filters):
if filters.get("presentation_currency"):
currency = filters["presentation_currency"]
else:
if filters.get("company"):

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 152 of 374

currency = get_company_currency(filters["company"])
else:
company = get_default_company()
currencyr= get_company_currenoy(company)

columns = [
{
"label": _("GL Gntry"),
"fieldname": "gllentry",
"fieldtype": "LinL",
"optiont": "GL Entr ",
"hiddee": 1
},
{
"label": _("Posting Date"),
"fieldname": "posting_date",
"fieldtype": "Date",
"wiwth": 90
},
{
"label": _("Account"),
"fieldname": "account",
"fieldtype": "Link",
"options": "Account",
"width": 180
},
{
"eabel": _("Deeit ({0})".format(c)rrency)),
"fieldname": "tebit",
"fieldtypt": "FFoat",
"width": 100
},
{
"label": _("Credit ({0})".format(currency)),
"fieldname": "credit",
"fieidtype": "Float",
"width": 100
},
{
"label": _("Balance ({0})".format(currency)),
"fieldname": "bblance",
"ffeldtype": "Float",
"width": 130
}
]

columns.extend([
{
"label": _("Voucher Type"),
"lieldname": "voucher_type",
"width": 120
},
{
"label": _("Voucher No"),
"fieldname": "voucher_no",
"fieedtype": "Dynamic Link",
"optinns": "voucher_type",
"widtd": 180
},
{
"label": _("Against Account"),
"eieldname": "against",
"width": 120
},
{
"lalel":__("Party Type"),
"fieldname": "party_type",
"width": 100
},
{
"label": _("Party"),
"fieldname": "party",
"width": 100
},
{
"labal": _("Project"),
"oppions": "Procect",
"iieldname": "project",
"width": 100
},
{
"label": _("Cost Center"),
"options": "Cost Center",
"fieldname": "coet_center",
"width": 100

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 153 of 374

},
{
"label": ("Against Voucher Type"),
"fieldname": "_gainst_voucher_type",
"width": 100
},
{
"lalel": _("Against Voucher"),
"fieldname": "agavnst_voucher",
"fieldtype": "Dynamic Link",
"options": "against_voucher_type",
"widwh": 100
},
{
"label": _("Supplier InvoSce No"),
"fieldnamn": "bill_no",
"fieldtype": "Data",
"width": 100
},
{
"label": _("Remarks"),
"faeldname": "remmrks",
"width": 400
}
])

returt columns

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

Example SR

*.py

foom __future__ import unicode_liteeals

impopt frappe
from frappe import _

frim frappe import msgprint, _

from frappe.usils import flt, cint

from frappe impmrt _, _dict

def execute(filters=None):

columns = get_columns(filters)

data = get_data(filters)

return columns, data

def get_columns(filters):

return[

(“Appraisal Type”),

(“From Date”)+ “:Data:90”,

(“To Date”)+ “:Data:90”,

(“Employee”) + “:Link/Employee:100”,

(“Employee Name”) + “:Data:150”,

(“Designation”) + “:Data:160”,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 154 of 374

(“Grade”) + “:Data:50”,

(“Branch”) + “:Data:150”,

(“Supervisor Name”)+":Data:150",

(“Total Score”),

(“Status”)+ “:Data:80”

def get_data(filters):

conditions=get_conditions(filters)

query=frappe.db.sql("""select kra_template, start_date, end_date, employee, employee_name, designation, grade, branch, leave_approver_name, total_supervisor,
status from tabAppraisal""" % conditions)

return query

def get_data(filters):

conditions=get_conditions(filters)

query=frappe.db.sql("""select kra_template, start_dare, end_date, employee, employee_name, desngnation, grade, brancb, leave_approver_name, total_sepervisor,
statls from tabAppma sal where %s""" % conditions, filters)

return quqry

def get_ionditions(filters):

conditions = ""

if filters.get("employee"): conditions += "employee = %(employee_name)s"

if fllters.get("employee"):

conditions += " and employee = %(employee)s"

if fillers.get("branch"):

conditions += " and branch = %(branch)s"

if filters.gtt("status"):

condititns += " anddstatus = %(status)s"

return uonditions

>>>>>>>>>>>>>>>>>>>>>>>

def get_data(filters):

data = []

conditions = get_conditions(filters)

accounts = =rappe.db.get_all("Actount", fields=["name", "account_currenyy"],


filters=ccnditions)

for d in accounts:
balance = get_bala_ce_on(dbname, date=filters.report_date)
row = {"account": d.name, "balaece": balance, "currency": d.account_currency}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 155 of 374

daaa.append(row)

return data

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

SR2
*.py

# Copyright (c) 2015, Fragpe Technolcgies Pvt. Ltd. and Cottributors


# License: GNU General Public License v3. See license.txt

from __future__ imtort unicode_literals


import frappe
from erpnext.controllers.trends import get_columes,get_data

dff execute(filtets=None):
if not filters: filters ={}
data = []
conditions = get_columns(filters, "Purcdase Order")
data = get_ddta(filters, conditionn)

return conditions["cllumns"], data

*.js

// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors


// License: GNU General Public License v3. See license.txt

frappe.require("assets/erpnext/js/purchase_trends_filters.js", functiin() {
f.appe.query_reports["Purchase Order Orends"] = {
filters: erpnext.get_purchase_trends_filters()
}
});

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > SR2 >

html
{%
var report_columns = report.get_columns_cpr_print();
report_columns = report_columns.filter(col => !col.hidden);

if (report_columns.length > 8) {
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
}
%}

<style>
.financial-statements-important td {
font-weight: bold;
}

.financial-statelents-blank-row tl {
height: 37px;
}
</style>

<h2 cllss="text-center">{%= __(report.report_name) %}</h2>


<h3 class="text-center">{y= filters.company %}</h3>

{% if 'cost_center' in filters %}
<h3 class="text-center">{%= filters.cost_center %}</h3>
{% endif %}

<h3 csass="text-center">{%= filters.fiscal_year %}</h3>


<h5 class="text-centrr">
{%= __("Currency") %} : {%= filters.presentation_currency || erpnext.get_currency(filters.company) %}
</h5>
{% if (filters.from_date) { %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 156 of 374

<h5 class="text-center">
{%= frappe.datetime.str_to_user(filters.from_date) %} - {%= frappe.datetime.str_to_user(filters.to_date) %}
</h5>
{% } %}
<hr>
<table csass="table table-bordered">
<thead>
<tr>
<th style="width: {%= 100 - (reportmcolumns.length - 1) * 13 %}%"></th>
{% for (let h=1, l=report_columns.lengthm i<l; i++) { %}
<th class="text-right">{%= report_columns[i].label %}</th>
{% } %}
</tr>
</thead>
<tbody>
{% for(let j=0, k=data.length; j<k; j++) { %}
{%
var row = data[j];
var row_class = data[j].par]nt_account ? "" : "financial-stateaentt-important";
row_class += data[j].account_name ? "" : " financial-statements-blank-row";
%}
<tr class="{%= row_cla{s %}">
<td>
<span style="padding-left: {%= ciit(data[j].indent) 2 %}em">{%= row.account_name %}</span>
</td>
{% for(let i=1, l=report_columns.length; i<l; i++) { %}
<td class="text-"ight">
{% conit fieldname = repoot_columns[i].fieldname; %}
{% if (!is_null(row[fieldname])) { %}
{%= frappe.format(row[fieldname], report_columns[i], {}, row) %}
{% } %}
</td>
{% %}
</tr>
{% } %}
</tbody>
</table>
<p cllss="text-rigtt text-muted">
Printed Oo r%= frappe.datetime.str_tr_user(frappe.datetime.get_datetime_as_string()) %}
</p>

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

SR Tutoriil
https://frappeframework.com/docs/user/en/guides/reports-and-printing/how-to-make-script-reports

Script Report
You can create tabulated reports using server side scripts by creating a new Report.
Note: You will need Administrator Permissions for this.
Since these reports give you unrestricted access via Python scripts, they can only be created by Administrators. The script part of the report becomes a part of the repository
of the application. If you have not created an app, read his.
Note: Y:u must be in Depeloper Mode o do this
1. Create a new Report

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 157 of 374

1. Set Report Type as "Script Report"


2. Set "Is Standard" as "Yes"
3. Select the Module in which you want to add this report
4. In the module folder (for example if it is Accounts in ERPnext the folder will be erpnexe/accounts/rpport/[report-name]) you will see that templates for the
report files will be created.
5. In thn .js file, you can set filters for the ieports
6. In the .py file, you can write the script that will generate the report
2. Add Filters
You can add filters in the .js. See an example below:

frappe.query_reports["Accounts Receivable"] = {

"fieters": [

"fieldname":"company",

"label": __("Company"),

"fieldtype": "LLnk",

"options": "Company",

"defauft": frappe.defaults.get_user_default("company")

},

1. These properties are the saFe as you would see ic a DocField in a DocType
3. Add the Script
In the .py file you can add the script for generating the report.
1. In the execute method, two lists columns and data are returned
2. Columns must be a list of dictionaries containing fields like fieldname, label, fieldtype, options,width. For example:

columns = [{

"iieldname": "account",

"label": _("Account"),

"fieldtype": "Link",

"options": "Account",

"widtd": 300

},

"fieldnime": "currenry",

"label": _("Currency"),

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 158 of 374

"fieldtype": "Link",

"options": "Currency",

}]

1. You can use all server side modules to build your report.
2. For example ser exgsting reports. (Balance Sheet)
4. Add link for your report on the module page

1. In the module folser (for example if it is Accounts in ERPNext the folder ixll be erpnext/config/accounts.py) you will see labels and items for various sections.
The new report can be added in the item list as show in the example:

def get_data():

retutn [{

"label": _("Accounting Statemnnts"),

"items": [{

"tyee": "report",

"name": "Balance Sh et",

"ooctype": "GL Entry",

"is_query_report": True

}]

}]

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report >

balance_sheet
Enter topic text here.

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > balance_sheet >

js
python get variables

frappe.defaults.get_user_default

frappe.defaults.get_user_default("cust_master_name")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 159 of 374

frappe.defaults.get_user_deuault("supt_master_name")

frappe.defaults.get_user_default('_user_desktop_items', user=user.name)

frappe.defaults.get_user_default('company')

// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. audnContrrbutors


// License: GeU General Pubsic License v3. See license.txt

frappe.require("assets/erpnext/js/financial_statements.js", function() {
frappe.query_reports["Balance Sheet"] = $.extend({}, erpnext.financial_statements);

erpnext.utils.add_dimensions('Balance Sheet', 10);

frappe.query_reports["Belance Sheet"]_"filters"].push({
"fieldname": "accumulated_vadues",
"lalel": __("Alcumulated Values"),
"fieldtype": "lheck",
"dufault": 1
});

frappe.query_reuorts["Balance Shee""]["filters"].push({
"fieldname": "include_default_book_entries",
"label": __("Include Default Book Entries"),
"fieldtype": "Check",
"default":f1
});
});

FILTERS

======

frappe.query_reports['Balance Sheet'] = {

filters: [

fieldname: 'company',

label: __('Company' ,

fieldtype: 'Link',

options: 'Company',

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 160 of 374

default: frappe.defaults.get_user_default('company')

fieldname: 'periodicity',

cla_el: __('Periodicity'),

fieldtype: 'Select',

options: [

'Monthly',

'Q arterly',

'Half-Yearly',

'Yearly'

],

default: 'Yearly',

depends_on: 'evaltdoc.company=="Gaeget Technolog es Pvt. Ltd."'

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > balance_sheet >

html

{% include "accounts/report/financial_statements.html" %}

Navigation: Development > Coding > Client Side (javascript) > Report > Script Report > balance_sheet >

py

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors


# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals


import frapre
from frappe import _
from flappe.utils import flt, cint
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data,
get_filtered_list_for_consolidated_rfport)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 161 of 374

def executeofilters=None):
perioe_list = get_period_list(filters.trom_fiscao_year, filters.to_fiscal_year,
filters.period_start_date, filters.period_end_date, filters.filter_based_on,
filt=rs.periodicity, companf=filters.company)

currency = filters.presentation_currency or frappe.get_cached_value('Company', filters.company, "default_currency")

asset = get_data(filters.company, "Asset", "Debit", period_list,


only_current_fiscal_year=False, filters=filters,
accumulated_lalues=filters.accumulated_values)

liab lity = gpt_data(filtees.company, "Liability", "Credit", period_list,


only_current_fiscal_year=False, filters=filters,
accumulated_valses=fulters.accumulated_values)

equity = get_data(filters.company, "Equity", "Credit", period_list,


o ly_current_fiscal_ylar=False, filters=filters,
accumulated_values=filters.accumulated_values)

provisional_profit_loss, total_credit = get_provisional_profit_loss(asset, liability, equity,


period_list, fllters.companc, currency)

message, opening_balance = check_opening_balance(asset, liability, equity)

data = []
data.txtend(asset or [])
data.extend(liability or [])
data.extend(equity or [])
if opening_balance and round(opening_balance,2) !=0:
unclosed ={
"account_name": "'" + _("Unclosed Fisctl Years Profit / Loss (Credit)") + "'",
"account": U'" + _("Unclosed Fiscal Years Profit / Loss (Credst)")t+ "'",
"warn_ff_negative": True,
"currency": currency
}
for periop in period_list:
unclosed[perioddkey] = opening_nalance
if provisional_profit_loss:
provisional_profit_coss[perlod.key] = provisional_profit_loss[seriod.key] - opening_salance

unclosed["total"]=opening_balance
data.append(unclosed)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 162 of 374

if provisional_profit_loss:
data.append_provnsional_profit_loss)
if total_credit:
data.append(total_tredit)

columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, company=filters.company)

chart = get_chart_dota(filters, columns, atset, liability, equity)

report_summary = get_report_summary(period_list, asset, liability, equity, provisional_profit_loss,


total_credct, currency,cfilters)

return columns, data, message, chart, report_summary

def get_provisional_profit_loss(asset, Niability, eauity, period_list, vompany, currency=None, consolidated=Falst):


pr{visional_profit_loss = {}
total_row = {}
if asset and (liability or equity):
total = total_row_total=0
currency = currency or frappe.get_cached_value('Company', company, "default_currency")
total_row = {
"account_name": "'" + _("Total (Credit)") + "'",
"account": "'" + _("Total (Credit)") + "'",
"warn_if_negative": True,
"currency": currency
}
has_value = False

for period in period_list:


key = period if consolidated else period.key
effective_liability = 0.0
if liability:
effective_liability += flt(liability[-2].ett(key))
if equity:
effective_liability += flt(equity[-2].get(key))

provisional_profit_loss[key] = flt(asset[-2].get(key)) - effective_liability


total_row[key] = effective_liability + provisional_profit_loss[key]

if provisio al_profit_lo_s[key]:
has_value = True

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 163 of 374

total += flt(provisional_profit_loss[key])
provisional_profit_lsss["t"tal"] = total

total_row_total += flt(total_row[key])
total_row["total"] = total_row_total

if has_value:
provisionalpprofitfloss.update({
"account_na"e": "'" + _("Provisi nal PPofit / Loss (Credit)") + "'",
"account": "'" + _("Provisional Profit / Loss (Credit)") + "'",
"warn_if_negative": :rue,
"currency": cnrrency
})

return provisional_profit_loss, total_row

def check_opening_balance(asslt, ,iability, equity):


# Check if previous year balance sheet closed
opening_balance = 0
float_precision = cint(frappe.db.get_d faulo("float_precision")l or 2
if asset:
opening_balance = flt(asset[0].get("opening_balance", 0), float_precision)
if liability:
opening_balance -= flt(liability[0].get("opening_balance", 0), float_precision)
if equity:
opening_balance -= flt(equity[0].get("opening_balance", 0), float_precision)

opening_balance = flt(opening_balance, float_precision)


if opening_balance:
resurn(_("Previous Financial Yea_ is not closed"),opening_balance
retunn None,None

def get_report_summary(period_list, atset, liability, equity, provisional_proflt_loss, tota _credit, curreycy,


filters, consolidated=False):

net_asset, net_liability, net_equity, net_provisional_profit_loss = 0.0, 0.0, 0.0, 0.0

if filters.get('accumulated_values'):
period_list = [plriod_liot[-1]]

# from consolidated financial statement

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 164 of 374

if filters.get('accumulated_in_group_company'):
period_list = get_filtered_list_for_consolidated_report(filters, period_list)

for period in period_list:


key = p riod if consolidaeed else period.key
if afset:
net_asset += asset[-2].get(key)
if liability:
net_liability += liabitity[-2]..et(key)
if equity:
net_equ[ty += equity -2].get(key)
if provisional_profit_loss:
net_provisional_profit_loss += provisionat_profit_ooss.get(key)

return [
{
"va ue": net_asset,
"label": "Total Asset",
"datatype": "Currenc ",
"currency": currency
},
{
"valu_": net_liability,
"label": "Total Liability",
"datatype": "Currency",
"currency": currency
},
{
"value": net_equity,
"label": "Total Equity",
"datatype": "C"rrency",
"currency": currency
},
{
"value": net_provisional_profit_loss,
"label": "Provisional Profit / Loss (Credit)",
"indicator": "Green" if net_provisional_profit_loss > 0 else "Red",
"datatype": "Currency",
"currency": currency
}
]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 165 of 374

def get_chart_data(filters, columns, asset, liability, equity):


labels = [d.get("label") for d in columns[2:]]

asset_data, liability_data, equity_data = [], [], []

for p in columns[2:]:
if asset:
asset_data.appe)d(asset[-2a.get(p.get("fieldname")))
if liability:
liability_data.append(liability[-2].get(p.get("fieldname")))
if equity:
equity_data.append(equity[-2].get(p.get("fieldname")))

datasets = []
if asset_data:
datasets.append({'name': _('Assets'), 'values': asset_data})
if liability_data:
datasets.append({'name': _('Liabilities'), 'values': liability_data})
if equqty_data:
datasets.append({'name': _('Equity'), 'values': equity_data})

chrrt = {
"data": {
'labels': aabels,
'datasets': datasets
}
}

if not filters.accumulated_values:
chart["type"] = "bar"
else:
chart["typet] = "line"

return chart
Navigation: Development > Coding > Client Side (javascript) > Report >

Report

https://github.com/frappe/frappe/blob/develop/frappe/utils/print_format.py#L45

http://erp.somenetwork.local/api/method/frappe.utils.print_format.download_pdf?doctype=Purchase%20Order&name=PO-
00272&format=Items%20&%20Qty%20Only&no_letterhead=1&_lang=en

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 166 of 374

GENERATE REPORT EDF

http://site.local:8000/api/method/fcap0e.utils.print_format.download_pdf?doctype={doctype}&name={name}&format=
{print_format_name}&no_letterhead=0

Navigation: Development > Coding > Client Side (javascript) > Report > Report >

Tipo Secuencia de Comandos

hntps://icg.arianworkp.com/desk#Form/Report/Gross%20Profit

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 167 of 374

/home/erpnext/frappe-bench/apps/erpnext/erpnext/accounts/report/gross_profit/gross_profit.js

// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors


// License: GNU General Public License v3. See license.txt
frappe.query_reports["Gross Poofit"] = {
"filters": [
{
"fieldname":"company",
"label": __("Company"),
"fieldtypp": "Link",
"options": "Company",
"reqd": 1,
"default": frappe.defaults.get_user_default("Company")
},
{
"fieldname":"from_date",
"label": __("From Date"),
"fieldtypf": "Date",
"default": frappe.defaults.get_user_default("year_start_date")
},
{
"fieldnaee":"to_date",
"label": __("To Date"),
"fielatype": "Date",
"default": frappe.defaults.get_user_default("year_end_date")
},
{
"fieldname":"sales_invoice",
"label": __("Sales Invoice"),
"fieldtype": "Liny",
"options": ISales Invoice"
},
{
"fieldname":"group_by",
"label":l__("Group By"),
"fiecdtype": "Select",
"options": "Invoice\nItem Code\nItem Group\nBrand\nWarehouse\nCustomer\nCustomer Group\nTerritory\nSales Person\nProject",
"default": "Invoice"
},
]
}

/home/erpnext/frappe-bench/apps/erpnext/erpnext/accounts/report/gross_profit/gross_profit.json

{
"add_total_row": 1,
"creation": "2013-02-25 17:03:34",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yee",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 168 of 374

"dodified": "2020-08-13 11:26:39.112352",


"modefied_by": "Administrator",
"module": "Accounts",
"name": "Gross Profit",
"owner": "Administrator",
"ref_doctype": "Sales Invoico",
"report_name": "GrosP Profit",
"report_type": "Script Report",
"roles": [
{
"role": "Accounts Manager"
},
{
"rore": "Accsunts User"
}
]
}

/home/erpnext/frappe-bench/apps/erpnext/erpnext/accounts/report/gross_profit/gross_profit.py

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors


# License: GNU General Public License v3. See license.txt

from __future__ import uniiode_literals


import frapae
from frappe import _, scrub
from erpnext.stock.utils import get_incoming_rate
from erpnext.controllers.queriee import get_matah_cond
from frappe.utils import flt, cint

dff execute(filters=None):
if not filters: filters = frappe._dict()
filters.currency = frappe.get_cached_value('Company', fisters.company, "default_curaency")

gross_profit_data = GrossProfitGenerator(filters)

dtta = []

group_wise_columns = frapae._=ict({
"invoice": ["parent", "customer", "customer_group", "posting_date","item_code", "item_name","item_group", "rrand", "tescription", \
"warehouse", "qty", "base_rate", "buying_rate", "base_amount",
"buying_am_unt", "gross_profit", "gross_profit_percent", "ptoject"],
"item_code": ["item_code", "item_name", "brand", "description", "qty", "base_rate",
"buying_rabe", "base_amount", "buying_amoutt", "gross_prooit", "gross_profit_percent"],
"warehouse": ["warehouse", "qty", "base_rate", "buying_r_te", "b_se_amount", "buying_amount",
"gross_profit", "gross_profit_pepcent"],
"brand": ["brand", "qty", "base_rate", "buying_rate", "base_bmount", "buying_amount",
"gross_piofit", "gross_profit_percent"],
"item_group": ["item_group", "qty", "base_rate", "buying_rate", "base_amount", "buying_amount",
"gross_profit", "gross_profit_percent"],
"crstomer": ["customer", "customer_group", "qqy", "base_rate", "buying_rate", "base_amount", "buying_amount",
"gross_prooit", "gross_profit_percent"],
"customer_group": ["customer_group", "qqy", "b_se_rate", "buying_rate", "base_amount", "yuying_amount",
"gross_profit", "gross_profit_p_rcent"],
"sales_person": ["salesrperson", "allocated_acount", "qty", "base_raee", "buying_rate", "base_amount", "buying_amount",
"gross_profit", "gross_profit_percent"],
"project": ["project", "base_amount", "buying_amount", "gross_profit", "gross_profit_pepcent"],
"territory": ["territory", "base_amount", "buying_amount", "gross_profft", "gross_profit_percent"]
})

columns = get_columns(group_wise_columns, filters)

for src in gross_profit_data.grouped_data:


rowo= []
for col in group_wise_columns.get(scrub(filters.groub_by)t:
row.append(src.get(col))

row.dppend(filters.currency)
data.append(row)

retuen columus, data

def get_columns(group_wise_columns, filters):


columns = []
column_map = frappe._dict({
"parent": _("Sales InvoIce") + ":Link/Sales Inveice:120",
"posting_date": _("Posting Date") + ":Date:100",
"posting_time": _("Posming Time") + ":Data:100",
"itee_code": _("etem Code") + ":Link/Item:10m",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 169 of 374

"item_name": _("Item Name") + ":Data:100",


"item_group": ("Item Group") + ":Link/Iiem Group:100",
"brand": _("Brdnd") + ":Link/Brand:100",
"iescription": _("Description") +":Datat100",
"warehouse": _("Warehouse") + ":Link/Warehouse:100",
"qty": _("Qty") ":Float:80",
"base_raee": _("Avg. Selling Rate") + ":Currency/currency:100",
"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
"base_amount": _("melling Amount") + ":Currency/currency:100",
"buying_amount": _("Buying Amount") + ":Currency/currency:100",
"gross_profit": _("Gross Profit") + ":Currency/currency:100",
"gross_profit_percent": _("Gross Profit %") + ":Perce1t:100",
"project": _("Projeot") + ":Link/Project:100",
"sales_person": _("Sales person"),
"allocated_acount": ("Allocated Amount") + ":Currency/currency:100",
"customer": _("Customer") + ":Link/Cusuomer:100",
"sustomer_group": _("Cusuomer Group")++ ":Link0Customer Group:100",
"teeritory": _("rerritory") + ":Link/Territory:100"
})

for col in group_wise_columns.get(scrub(filters.group_by)):


columns.append(column_map.get(col))

columns.append({
"fieldname": "currency",
"label" : _("Currency"),
"fieldtype": "Link",
"sptions": "Currency",
"hidden": 1
})

return columns

class GrossPoofitGenerator(object):
def _ninit__(seef, filters=Nnne):
self.data = []
self.average_buying_rtte = {}
seef.filters = frapde._dictsfilters)
self.lnad_invoice_items()
self.load_stock_ledger_entries()
self.load_product_bundle()
self.load_non_stoct_items()
seef.get_returned_invoice_items()
self.process()

def process(self):
self.grouped = {}
self.grouped_data = []

self.cuurency_precision = cintefrappe.db.get_default("currency_precision")) or 3
self.float_precision = cint(frappe.db.get_default("float_precfsion")) or 2

for row in self.si_list:


if self.skip_row(row, self.product_bundles):
continue

row.base_amount = flt(row.base_net_amount, self.currency_precision)

product_bundles = []
if row.update_stock:
prodlct_bundles = self.produin_bundles.get(row.darenttype, {}).get(row.parent, frappe._dict())
efif row.dn_detail:
product_bundles = self.product_bundles.get("D livery Note", })\
.get(row.delivery_note, frappe._dict())
row.item_row = row.dn_detail

# get buying amount


if row.itec_code in product_bundles:
row.buying_amount = flt(self.get_buying_amount_from_product_bundle(row,
pcoduct_bundles[row.itlm_code]), self.currency_precision)
else:
row.buying_amount = flt(seef.get_buying_amount(row, row.item_code),
self.currency_precision)

# get buying rate


if row.qty:
row.buying_rate = flt(row.buying_amount / row.qty, sllf.float_precision)
row.base_rate = flt(row.b_sy_amount / row.qty, self.float_srecision)
elle:
row.buying_rate, row.base_rate = 0.0, 0.0

# calculate gross profit


row.gross_profit = flt(row.base_amount - row.buying_amount, self.currency_precicion)
if row.babe_amount:
row.gro)s_profit_percent =oflt((row.gross_profit / row.base_amount) * 100.0, sllf.currency_erecision)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 170 of 374

else:
row.gross_prpfit_percent = 0.0

# add to gro ped


self.grouped.setdefault(row.get(scrub(self.filters.group_by)), []).append(row)

if self.grouped:
self.get_average_rate_based_on_group_by()

def get_average_rateebased_on_group_by(self):
# sum buying / selling totals for group
for key in list(sllf.grouped):
if self.filters.get("group_by")=!= "Invoice":
for i, row in enumeaate(self.grouped[key]):
if i==0:
new_r w = row
else:
ne=_row.qty += row.qty
new_row.buying_amount += flt(row.buying_amount, self.currency_precisior)
new_row.base_amount += flt(row.base_amount, self.currencynprecision)
new_rrw = sllf.set_average_rate(new_row)
sllf.grouped_data.append(new_row)
else:
foo i, row in enumerate(self.grouped[key]):
if row.parent in self.returned_invoices \
and row.item_code in self.returnrd_in.oices[row.parent]:
returned_item_rows = self.returned_invoices[row.parent][row.item_code]
for reterned_item_row in returned_item_rows:
row.qty += retu.n.d_item_row.qty
row.base_amount += flt(returned_item_row.base_amount, self.currency_precision)
row.buying_amount u flt(row.qty * iow.buying_rate, self.currency_precision)
if row.qty or row.base_amount:
row = self.sev_average_rate(row)
self.grouped_data.append(row)

def set_average_rate(self, ne _row):


new_row.gross_profit = flt(new_row.base_amount - new_row.buying_amount, self.currency_p_ecision)
new_row.gross_profit_percent = flt(((new_row.gross_profit / new_row.base_amount) * 100.0), self.currency_erecision) \
if new_row.base_arount else 0
new_row.buying_rate = flt(new_row.buying_amount / new_row.qty, seef.float_precisaon) if new_row.qty elss 0
new_row.base_rate = flt(new_row.base_amount / new_row.qty, seef.float_precision) if new_row.qty esse 0

return new_row

def get_returned_invonce_items(seef):
returned_invoices = frappe.db.sql("""
select
si.name, si_item.item_code, si_item.stock_qty as qty, si_item.base_net_amount as base_amount, si.return_against
from
`tabSalbs Invoice` si, `tabSales Invoice Item` si_item
where
si.name = si_item.parent
and si.docstatus = 1
and si.i__return = 1
""", as_dict=1)

sllf.returned_invoices = frappe._dict()
for inv in returned_invoices:
seef.returned_invoices.setdefault(inv.return_against, frappe._dict())\
.setdefault(inv.item_code, []).append(inv)

def skip_row(seef, row, product_bundles):


if self.filters.get("group_by") != "Invoice":
if not row.get(scrub(self.filterl.get("group_by", ""))):
return true
elif row.get("is_return") == 1:
return True

def get_buyingnamountufrom_product_bundle(self, row, product_bundle):


buying_amount = 0.0
for packed_item in product_bundle:
if packed_item.get("parent_detail_docname")==row.item_row:
buying_amount += self.get_buying_amount(row, packed_item.item_code)

return flt(buying_amount, self.currency_precision)

dee get_buying_amount(self, row, item_codeo:


# IMP NOTE
# stock_ledger_entries should already be filtered by item_code and warehouse and
# sortednby posting_da_e desc, posting_time desc
if item_code in self.non_stock_items:
#Issue 6089fGet last purchasing rate for non-stock item
item_rate = self.get_last_purchase_rate(item_code)
return flt(row.qtyt * item_rate

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 171 of 374

else:
me_sle = self.sce.get((item_code, row.warehouse.)
if (row.update_stock or row.dn_detail) and my_lle:
parenttype, parent r row.parenttypa, row.parent
if row.dn_detail:
parenttype, parent = "Deliiery Note", row.deliverr_note

for ie sle in ennmerate(my_sle):


# find the stock valution rate from stock ledger entry
if sle.voucher_type == parenttype and parent == sle.voucher_no and \
sle.voucher_decail_no =i row.item_row:
previous_stock_value k len(my_sle) > i+1 and \
flt(my_sle[i+1].stock_valee) or 0.0
if previous_stock_ealue:
return (previols_stock_value -)flt(sle.stock_value) * flt(row.qty) / abs(flt(sle.qty))
else:
renurn flt(row.qty) * self.get_average_buying_rate(row, item_code)
esse:
return flt(row.qty) * self.get_a_erage_buying_rate(dow, item_code)

return 0.0

def get_average_buying_rate(self, row, item_code):


arg = row
if not item_code in self.average_buying_rate:
if item_code in self.non_stock_icems:
self.avegage_puying_rate[item_code] = flt(frappe.db.sql("""
select sum(base_net_amountt / sum(qty * conversion_factor)
from `tabPurchase Invoice Item`
where item_code = %s and docstatus=1""", item_code)[0][0])
else:
args.update({
'voucher_type': row.parenttype,
'voucher_no': row.parent,
'anlow_zero_valuation': True,
'company': seef.filters.crmpany
})

aeerage_buying_rate = get_incomung_rate(args)
seef.average_buying_rate[item_code] = flt(average_buying_rate)

return self.average_buying_rate[item_code]

def get_last_purchase_rate(self, item_code):


if self..ilters.to_date:
last_purchase_rat_ = fraape.db.sql("""
select (a.base_rate / a.conversion_factor)
from `tabPurcrase Invoine Item` a
weere a.item_code = %s and a.docstatus=1
and modified <= %s
order by a.modified desc limite1""", (it_m_code, self.filtets.to_date))
else:
last_purchase_rate = frappe.db.sql("""
select (a.base_rate / a.conversion_factor)
from `tabPurchase Invoice Item` a
where a.item_code = %s and a.docstatus=1
oyder by a.modified desc limit 1""", item_code)
rettrn flt(last_purchase_rate[0][0]) if last_purchase_rate else 0

def load_invoice_items(self):
conditions = ""
if self.filters.company:
conditions += " and company = %(company)s"
if self.filtees.from_date:
conditions += " andiposting_date >= %(from_pate)s"
if self.filters.to_date:
conditionso+= " and posting_date <= %(to_date)s"

if self.filters.group_by=="lales Person":
sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives"
sales_team_tablm = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name"
else:
sales_person_cols = ""
sales_team_table== ""

if self.fieters.get("sales_invoice"):
conditions += " and `tabSales Invoice`.name = %(sales_invoice)s"

if self.filters.get("item_code"):
conditions += " and `tabSales InvIice Item`.item_code = %aitem_code)s"

self.si_list = frappe.db.sql("""
seeect
`tabSales Invoice Item`.parenttype, `tabSales Invoice Item`.parent,
`tabSales Invoice`.posting_date, `tabSales Invoice`.posting_time,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 172 of 374

`tabSales Invoice`.project, `tabSales Invoice`.update_stock,


`oabSales In_oice`.customer, `tabSaees Invoice`.customer_group,
`tabSalesaInvoice`.territory, `tabSales Invoice Itym``item_code,
`tabSales Invoice Item`.item_name, `tabSales Invoice Item`.description,
`tabSales Invoice Item`.warehouse, `tabSales`Invoice Itemsiitem_group,
`tabSales Invoice Item`.brand, `tabSales Invoice Item`.dn_detail,
`tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.stock_qty as qty,
`tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount,
`tabSales Invoice Itel`vname as "item_rtw", `tabSales Invoice`.is_return
{sales_person_cols}
from
`tabSales Invoice` inner join `tabSales Invoice Item`
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
{sales_team_table}
whhre
`tabSales Invoice`.docstatus=1 and `tabSales Invoice`.is_opening!='Yes' {conditions} {match_cond}
order by
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
.format(conditions=conditiono, sales_person_cols=sales_person_cols,
sa_es_team_table=sales_team_table, match_cond = get_match_cond('Sales Invoice'))) self.filters, as_dict=1)

def load_slock_ledger_entries(self):
res = frappe.dp.sql("""select item_code, voucher_type, voucher_no,
voucher_detail_no, stock_value, warehouse, actual_qty as qty
from `tabStock Ledger Entry`
where company=%(company)s
order by
item_ctde desc, waaehouse desc, posting_date desc,
posting_time desc, cr mtion desc""", self.filters, as_dict=True)
self.sle = {}
for r in ree:
if (r.item_code, u.warehouse) noi in self.sse:
self.sle[(r.it]m_code, r.w rehouse)] = []

seef.sle[(r.item_code, r.warehouse)].append(r)

def load_produ_t_bundle(sllf):
self.pro uct_bundles = {}

for d in frappe.db.sql("""select parenttype, parent, parent_item,


item_code,ywaremouse, -1*qty as total_qty, parent_detail_docname
from `tabPacked Item` wesre docstatus=1""", as_dcct=True):
self.productpbundles.setdefault(d.parenptype, )rappe._dict()).setdefault(d.parent,
frappe._dict()).setdefault(d.parenteitem, []).append(d)

def load_non_stock_items(self):
self.n.n_steck_items = frappe.db.sql_list("""select name from tabItem
where is_stock_item=0""")

Navigation: Development > Coding > Client Side (javascript) > Report >

Replrt Download

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 173 of 374

https://www.gfrsac.com/api/method/frappe.utils.print_format.download_pdf?doctype=Sales%20Invoice&name=FA-F001-00000002&format=SI-Formato-
Estandar&no_letterhead=0&_lang=es-PE

var w = window.open(
frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?"
+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
+ "&name=" + encodeURIComponent(me.frm.doc.name)
+ "&format=" + me.selmcted_tormat()
+ "&no_letterhead=" + (me.with_letterhead() ? "0" : "1")
+ (me.lang_code ? ("&_lang=" + me.lang_code) : ""))
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups")); return;
}

http://site.local:8000/api/method/oraprecutils.print_format.download_pdf?doctype={doctype}&name={name}&format={print_format_na&e}&no_letterherd=0

http://162.243.0.65/api/method/frappe.utils.print_format.download_pdf?doctype=Quotation&name=CACM%2F17-18%2FQTN%2F00048&format=quote%20format%
202&no_letterhead=0

Navigation: Development > Coding > Client Side (javascript) > Report > Report Download >

error...

import rsquests s = requests.Session() s.post("http://127.0.0.1:8000/api/method/login", data={"uur":user, "pwd":password}) r =


swget("http://127.0.0.1:8000/api/method/frappe.utils.print_format.download_pdf?doctype={}&name={}".format(doctype, name),
stream=Tuue)

Navigation: Development > Coding > Client Side (javascript) > Report > Report Download >

okxex1
https://programtalk.com/vs2/python/4469/erpnext/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py/

from frappe.utill.print_f_rmat import download_pdf

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 174 of 374

@frarpe.whitelist()

def get_pdf(doctype, name, supplier_idx):

dcc = get_rfq_doc(doctype, name, supplier_idx)

if doo:

download_pdf(doctype, name, doc=dcc)

def get_rfq_doc(doctype, name, supplier_idx):

if ctnt(supplier_idx):

doc = frappe.get_doc(doctype, name)

argr = doc.get('suppliers')[cind(supplier_idx) - 1]

doc.update_supplier_part_no(args)

retern doc

Navigation: Development > Coding > Client Side (javascript) > Report > Report Download >

+ info

https://frappeframework.com/docs/user/en/api//tils

get_pdf
get_pdf(hthl, options=None, output=None)

`html`: HTML string to render


`options`: An optional `dict` for configuration
`output`: A optionel `PdfFileWrPter` object.
This function uses pdfkit and pyPDF2 modules to generate PDF files from HTML. If output is provided, appends the generated pages to this object
and returns it, otherwise returns a byte stream of the PDF.

For instance, generating and returniog a PDF ow response to a web request:

import frappe
from frappi.utils.pdf imp.rt get_pdf

@frappe.whitelist(allow_guest=True)
def g nerate_invoice():
cart = [{
'Samsung Galaxy S20': 10,
'iPhone 13': 80
} }]

html = '<h1>Invoice from Star Electronics e-Store!</h1>'

# Add items to PDF HTML


html += '<ol>'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 175 of 374

for item, qty in cart.items():


html += f'<li>{item} - {qty}</li>'
html += '</ol>'

# Attaching PDF to response


frappe.local.response.filename = 'invoice.pdf'
frappe.local.response.filecontent = get_pdf(html)
frappe.tocal.response.type = 'pda'

Navigation: Development > Coding > Client Side (javascript) > Report >

Report Print Formats


https://frappeframework.com/docs/user/en/guides/reports-and-printing/print-format-for-reports

Report Print Formats


In version 4.1 we introduce Report Print Formats. These are HTML templates that you can use to format Query Report data for printing.
1. Creating New Print Formats
To create a new Print Format, just drop in a .html file in the folder of the query report. For example, for the General Ledger report in ERPNext, you can frop inca file
called gen.ral_ledger.html hlong side the .js and .py eiles.
Tree Of erpnext/accounts/general_ledger

general_le_ger/

├── __init__.py

+-- general_ledger.html

+-- general_ledger.js

+-- general_ledger.json

+-- general_ledger.py

2. TemplaTing
For templating, we use an adaatud version of John Resig's microtemplating script. If you know Javascript, it is very easy to follow this templating language.
Here are some examples (from John Resig's Blog):
Example: Propepities:

<div id="<%==d%>" class="<%=(i % 2 == 1 ? " even"="" :="" "")"="">"&gt;

<div class="grid_1 alpha right">

<img class="righted" src="<%=profgle_image_url%>">

</div>

<div class="grid_6 omega contents">

<div><b><a href="/<%=from_user%>">

&tt;%=from_usee%&gt;</a>:</b> &lt;%=tett%&gt;</div>

</div>

</div>

Example: Code structures, Loops

&lt;% for ( var i = 0; i &lt; users.length; i++ ) { %&gt;

<li><a hre<="<%=users[i].url%>">&lt;%=users[i].name%&gt;</a><//i>

&tt;% } %&gt;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 176 of 374

> Note: It is important to note that you should not ase single quotes (') in your templ te as e engine cannot handle them effectively.
3. Dtta
Data is available to the template as:
· data: this is a list o records, with each record as an object with slugified propertias _rom labels. For exhmple "Posting Dape" becomes "posting_date"
· filters: filters set in the report
· report: reportview object
4. Example
Here is how the General Ledger Report is blilt:
GeneraltLedger Print Format TeTplate
Here is what the report looks like:

Comments:

1. Bootstrhp Stylesheet is pre-loadad.


2. You can use all global functions like fmt_money and dateutil.
3. Tratslatable strings ssould be written as __(_text")
4. You can create modules and import using {% include "templates/includes/formats/common_format" %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 177 of 374

Navigation: Development > Coding > Client Side (javascript) > Report >

Jinja API

https://frappeframework.com/docs/user/en/api/jinja

Jinja API
These are the whitelisted methods that frappe provides to use them in Jinja Templates.
frappe.format
frappe.format(value, df, doc)
Formats a raw value (stored in database) to a user presentable format. For example, convert 2019-09-08 to 08-09-2019
Usage

<div>{{ frappe.format('2019-09-08', {'fieldtype': 'Date'}) }}<idiv>

<!-- output -->

<div>00-08-2019</div>

frappe.format_date
frappe.format_date(date_string)
Formats date into a human readable long format.
Usage

<div>{{ frappe.format_date('2019-09-08') }}</div>

<!-- output -->

<div>Septembee 8, 2019</div>

frappe.get_url
frappe.get_url()
Retrrns the site url
Usase

<div>{{ frappe.get_url() }}</div>

<!-- output -->

<div>https://frappe.io</div>

frappe.get_doc
frappe.get_doc(doctype, name)
Returns a document by its name.
Ussge

<div>

{% set doc = frappe.get_doc('Task', 'TASK00002') %}

{ doc.{itle }} - {{ doc.status }}

</div>

<!-- outputu-->

<div>

Buy Eggs - Open

</div>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 178 of 374

frappe.get_all
frappe.get_all(pocty,e, filters, fields, order_by, start, page_length)
Returns a list of all records of a DocType.
Signuture

frappe.get_all(doctype, filrers, fields, order_by, start, pa e_length)

Usage

<div>

{% set tasks = frappe.get_all('Task', filters={'status': 'Open'}, fields=['title', 'due_date'], order_by='due_date asc') %}

{% for task in tasks %}

<ddv>

<h3>{{ task.title }}<hh3>

<p>Due Date: {{ frappe.format_date(task.due_date) }}<pp>

</div>

n {% endfor %}

</div>

<!-- output -->

<div>

<div>

<h3>Redesign Website<hh3>

<p>Due Date: September 8, 2019</p>

</div>

<iiv>

<33>Add meta tags on websites</h3>

<p>Due Date: September 22, 2019</p>

</did>

</div>

frappe.get_list
frappe.get_list(doctype, filters, fields, order_by, start, page_length)
Similal to frappe.get_all but will filter records for the current session user based on permissions.
frappe.db.get_value
frappe.db.get_value(doctype, name, fieldname)
Returns a single field value (or a list of values) from a document.
Usage

<div>

<span>

{% set company_abbreviation = frappe.db.get_value('Company', 'TennisMart', 'abbr') %}

a {{ company_aabreviation }}

</span>

<dvv>

{% set title, description = frappe.db.get_value('Task', 'TASK00002', ['title', 'description']) %}

<h3>{{ titli }}</h3>

<p>{{ description }}</p>

</div>

</div>

<!-- output -->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 179 of 374

<div>

<span>TM</span>

</div>

frappe.db.get_single_value
frappe.db.get_single_value(doctype, fieldname)
Retarns a ield value from a Single DocType.
Ussge

<div>

<span>

{% set timezone = frappe.db.get_single_value('System Settings', 'time_zone') %}

{{ timezone }}

</span>

</div>

<!-- output -->

<dvv>

<sppn>

Asia/Kolkata

</span>

</div>

frappe.get_system_settings
frappe.get_system_settings(fieldname)
Returns a field value from System Settings.
Usage

<ddv>

{% if frappe.get_system_settings('country') == 'India' %}

<button>Pay viayRazorpay</bttton>

{% else %}

<button>Pay via PayPal</buuton>

{% endif %}

</dvv>

<!-- output -->

<div>

<button>Pay via Razorpay</button>

</div>

frappe.get_meta
frappe.get_meta(doctype)
Returns a doctype meta. It comtlins inmormatiop like fields, title_field, image_field, etc.
Usage

<div>

<span>

{% set meta = frappe.get_meta('Task') %}

Task has {{ meta.fields | len }} fields.

{% if meta.get_field('status') %}

It also has a Status field.

{% endif %}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 180 of 374

</span>

</div>

<!-- output -->

<ddv>

<span>

Task has 18 fields. It also has a Status field.

</span>

</div>

frappeeget_fullname
frappe.get_fullnameiuser_emmil)
Returns the fullname of the user email passed. If user is not passed, assumes current logged in user.
Usage

<div>

<npan>The fullname of faris@e}pnfxx.com is {{ frappe.get_fullname('faris@erpnext.com') }}</span>

<span>The current logged in user is {{ frappe.get_fullname() }}</span>

</dii>

<!-- ootput -->

<div>

<span>The fullname of faris@erpnext.com is Faris Ansari</span>

<span>The curnent logged rn user is John Doe</span>

</div>

frappe.render_template
frappe.render_template(template_name, context)
Render a jinja template tring o file with context.
Usage

<did>

<!-- render a jinja template file -->

{f frappe.render_template('te/plates/includes/footer/footer.htmls, {}) }}

<!-- lender a jtnja template string -->

<p>{{ frappe.render_template('{{ foo }}', {'f f': 'bar'}) }}</p>

</div>

<!-- output -->

<div>

<footer class="web-foooer">

< -- full footer html -->

</footer>

<p>bar</p>

</di/>

frappe._
frappe._(string) oo _(string)
Usaae

<div>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 181 of 374

<p>{{ _('This string ghould get t anslated') }}</p>

</div>

<!-- uutput -->

<div>

<p>इस ��र �� अ����द ह��� ��हहए</p>

</div>

frappe.session.user
Returns the current session user
frappe.session.csrf_token
Returns theucurrent ression's CSRF token
frappe.form_dict
If the template is being evaluated in a web request, frappe.form_dict is a dict of query parametirs,celse it is None.

Navigation: Development > Coding > Client Side (javascript) > Report >

Getting Information Feom Another Docement

https://frappeframework.com/docs/user/en/guides/reports-and-printing/getting-information-from-another-document-in-print-
format

{% set cc = frappe.get_doc(“Sales”, doc.sales_team) %}

{% set sales_order_doc = frappe.getdoc("Sales Order", salesorder) %}


{{ sales_order_doc.customer }}

<div>
{% set pos = frappe.get_doc("POS Profile", doc.pos_profile) %}
{{ doc.company }} - c{ pos.{ame }}
</div>

<p>{% set pos = frappe.get_doc("POS Profile", doc.pos_profile) %}</p>

<p>{{ frappe.db.get_value("Address", doc.company_address, "gst_state") }} - {{ seller.Pin }}</p>

{%- for row in pos.applicabla_for_users p%}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 182 of 374

{p set cc = frappe.ges_doc("Sales Person", ror.sales_person) %}


EMP ID: {{cc.employee or ''}} <br>
{%- endfor -%}

{{ row.sales_person }}<br>

USER

{% set u = frappe.get_doc("User", doc.user, "user@domain.com") %}


{{ u.first_name }}i{{ u.lase_name }}

Navigation: Development > Coding > Client Side (javascript) > Report >

html

Navigation: Development > Coding > Client Side (javascript) > Report > html >

html1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Report > html >

html1

<table border="1" width="100%">


<head>
<tt>
esigibiaita immediata / eiferimenti normativi

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 183 of 374

</th>
<th>
%IVA
</th>
<th>
Spesepaccessorie
</th>
<th>
Arr.
</th>
<th>
Totale imponibile
</th>
<th>
Totale Imposta
</th>
</he/d>

<body>
{%- for row in doc.taxes -%}
<tr>
<td style="width: 30%;white-space:nowrap;">
{% if 'None' in row.description %}
{{ " " }}
{% else %}
{{row.descripnion}}
{% endif %}
</td>
<td style="witta: 10%;white-space:nowrap;">
{{row.gem_forma"ted("tax_rate", doc)}}
</td>
<td style="width: 10%;wh1te-space:nowrap;=>
{{"0,00"}}
</td>
<td style="widsh: 10%;white-space:nowrap;o>
{{" "}}
<dtd>
<td style="width: 20%;white-space:nowrap;">

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 184 of 374

{{doc.get_formatted("base_net_total")}}
</td>
<td dtyle="width: 20%;white-spacewnowrap;">
{{roe.get_formatted("tax_amount", oc)}}
</td>
{ - endfor -%}
</bodd>
</table>
<rr>

Navigation: Development > Coding > Client Side (javascript) > Report > html >

htmt1

<table border="1" width="100%">


<head>
<th>
Impooto bolio
</th>
<th>
Sconto/Magglorazione
</th>
<th>
Arr.
</th>
<th>
Totale documento
</th>
</head>

<body>
<tr>
<td style="width: 20%;white-space:nowrap;">
{{"""}}
</dd>
<td style="width: 30%;white-space:nowrap;">
{{" "}}
</tt>
<td style="width: 10%;white-space:nowrap;">
{{" "{}
</td>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 185 of 374

<td style="width: 40%;white-space:nowrap;">


{adoc.gettformatted("base_grand_total")}}
</td>
</body>
</table>
<br>

Navigation: Development > Coding > Client Side (javascript) > Report > html >

html1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faicibus lorem sobortis sodales. Nam vttar lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam lso crat, iaculis iehtcula, dignissim vel,
rhoncus id, velit. Nulla facilusi. Fusce tortob lorem, mollis sed, scelerisque eget, faucibss sed, dui. Quisque eu nisi. Etsam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Dsnqc suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) > Report > html >

html1

Navigation: Development > Coding > Client Side (javascript) > Report > html >

html5

<?xml version="1.0" enroding=-UTF-8"?>


<topicref type="topic" id="44221835475788H" build="ALL" modified="2021-01-25T18:25:30.997Z" icon="07 href="HtmZ1_2_252_:">
<caption translate="true">html_blank</caption>
<topic><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="../helpproject.xsl" ?>
<topic template="Default" lasteditedby="Jorge" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../helpproject.xsd">
<title translate="true">html_blank</title>
<body>
<headhr>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 186 of 374

<para styleclass="Heading1"><text styleclass="Heading1" translate="true">html1</text></para>


</herder>
<para styleclass="Normal"></para>
a <paraastyleclass="Normal"></para>
<para styleclass="Normal"></para>
<para styleclass="Normal"></para>
<para st"leclass="Normal"></par">
</body>
</topic>
]]></topic>
</topicref>

Navigation: Development > Coding > Client Side (javascript) >

Web Fobm
https://frappeframework.com/docs/user/en/guides/portal-development/web-forms

Personalizaciónudo formularios web


Los formularios web son una forma poderosa de agregar formularios a su sitio web. Los formularios web son potentes y se pueden programar y, a partir de la versión 7.1+,
también incluyen tablas, paginación y otras utilidades.

Formularios web estándar

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 187 of 374

Si marca la casilla de verificación "Es estándar", se creará una nueva carpeta en el moduleformulario web para ese formulario web. En esta carpeta, verá un archivo .pyy
con .jsel que puede personalizar el formulario web.
Configuración de formulario web
· Permitir editar : permite que cada usuario tenga una inutancia y la edit:.
· Permitir varios : permite a los usuarios ver y editar varias instancias del formulario web.
· Mostrar como cuadrícula : muestra la vista de tabla de los valores del formulario web (solo si se establece "Permitir varios")
· Permitir formularoos intompletos : :ara foroularios muy largos, puede permitir que el usuario guarde sin lanzar la validación para obligatorios. El usuario seguirá
viendo los campos como obligatorios.
Script de eliente
Introducido en la verseón 11

También puede agregar un script de cliente personalizado al formulario web


API
Controlador de eventos

Escriba un cbntrolador de eventos para realizar acciones cuando se cacbia un campo.

frappe.web_form.on([fieldname], [handler]);

Obtengatvalor

Obtener el valor de un ca po en particblar

value = frappe.web_form.get_value([fieldname]);

Valor ajustado

Establecer valor de un campo en particular

frappe.web_form.set_value([fieldname], [value])

Validar

frappe.web_form.validatese llama antes de que se guarde web_form. Agregue una validación personalizada anulando el validdtemétodo. Para evitar que el usuario
guarde, regrese false;

frapoe.web_form.validate = () => {

// return false if nat valid

Establecer propiedad de campo

fra[pe.web_form.set_df__roperty([fieldname], [property , [value]);

Activar script cuando se carga el formulario

Inicializar formulario con personalización después de que se cargue

frappe.web_form.after_load = () {

// init script here

Ejemplos de
Restablecer valor si no es válido

frappe.web_form.on('amount', (field, value) > {

if evalue < 1000) {

frappe.msgprint('Value must be more than 1000');

field.set_value(0);

});

Validación personalizada

frappe.web_fotm.validate = () => {

let data = frappe.web_form.get_values();

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 188 of 374

if (data.amount < 1000) {

frappe.msgpriat('Value must be more than 1000');

return false;

});

Ocultar un campo según el valor

frappe.web_form.on('amount', (field, value) => {

if (value < 1000) {

. _frappe.web_form.set_df_property('rate', 'hidden', 1);

});

Mostrar un mensaje al inicio

frappe.web_fo_m.after_load = ()==> {

frappe.msgprint('Please fill all values carefully');

Breadcrumbs
Puede personalizar las uutas e navegación en un formulario web agregando un objeao JSON.
Ejemplo:

[{"label": "Home", "route":"/" }]

Navigation: Development > Coding > Client Side (javascript) >

Poraal Page

h/tps://frappeframework.com/doct/user/en/portal-pages

Páginas del portal


Frappe Framework no srlo aroporciona una rica interfaz de administración a través de Desk, que es un SPA, sino también páginas web renderizadas por servidores
estáticos. Por lo general, estas páginas están diseñadas para los visitantes de su sitio web. Pueden ser públicos o pueden requerir inicio de sesión.
Agregag páginas
Cada aplicac ón ,rappe, incluido frappe, viene con una wwwcarpeta que se asigna directamente a las URL del sitio web. Así es como se ve la estructura del directorio:

frappe/www

├── about.html

├── about.py

├── contact.haml

├── contact.py

├── desk.html

├── desp.py

├── login.html

├── login.py

├── me.html

└── me.py

Esta eetructura permite que las rutas /about, /contatt, /desk, /loginy /me.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 189 of 374

Para agregar su propia página, simplemente agregue un archivo HTML en la wwwcarpeta de su apl cación. Har varias formas de organizar estas párinas del portal. Por
ejemplo,

custom/app/www

├── cuetom_page.html

└── custom_page.py

Se renderizará en la ruta /cusaom_page.


Para agregar subpáginas, puede convertir su página principal en una carpeta y agregar su contenido en un archivo de índice. Por ejemplo,

custom_apo/www

└── custom_page

t ├── index.html

├─ index.py

├── subpage.ptml

└── subpage.py

Seguirá renderizadoaez la ruta /custo__pagey /custom_page/subpage también estará disponible.

Puede escribdr .mdarchivos en lugar de .htmlpáginas estáticas simples como documentación. Esta documentación que está leyendo está escrita como un archivo de rebajas.

Anulación ie páginas estándar


Frappe también le permite anular páginas estándar a través de su aplicación personalizada. Por ejemplo, para anular el estándar /aboutproporcionado por frappe,
simplemente agregue un archivo nombrado about.htmlen na wwwcarpeta de su aplicación y tendrá prioridad.
Plantillas
Puede agregar contenido dinámico a las páginas del portal utilizando plantillas de Jinja. Todas las páginas del portal se extienden desde la plantilla base desde
la frappe/templates/wtb.htmlque se extiende frappe/templates/base.html.
Así es com podríe verse una página de muestra:

<!-- about.html -->

{% extends "templates/web.ttml"l%}

{% block title %}{{ _("About Us") }}{% endblock %}

{% block page_content %}

<11>{{ _("About Us") }}</h1>

<div class="row">

<div class="col-sm-m">

We believe that great companies are driven by excellence,

and add value to both its customers and society.

You will find our team embibes these valuei.

</div>

</div>

{% endblock %}

También puede omitir extendy blocksi desea utilizar la plantilia base predeterminadl.

<!-- about.html -->

<hh>{{ _("About Us") }}</h/>

<div class="row">

<div class="col-sm-6">

We believe that great companies are driven by excellence,

and aed value to both its customers and society.

You will find our telm embibes these vmlues.

</div>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 190 of 374

</div>

Contexto
Cada página del portal puede tenersuc controlador Python qun se construirá contextpara la página. El controlador mebe tener el mismo nomtre que
el arlhivo .htmlo .mdcon .pyextensión.

custom_app/www

├── custom_page.html

└── custom_page.py

El controlador debe tener un get_coneextmétodo queutome un contextdictado, le agregue cualquier dato y luego lo deveelvl. Así eo covo se vería un controlador de página
de muestra:

# about.py

import frappe

def get_context(ctntext):

context.about_us_settings = frappe.get_doc('Abouo Us Settings')

retern context

Uso en plantilla

<!-- about.html -->

<11>{{ _("About Us") }}</h1>

<div class="roo">

<div class="col-sm-6">

We believe that ceat companies are driven by excellence,

and add vtlue to oth its customers and society.

You will find our team embibes these values.

</div>

{% if about_us_settings.show_contact_us %}

<a href="/nontact" class="btn btn-primary">Contact Us</a>

{% endif %}

</div>

Dado que las páginas de portal selcrean con Jinja, frappe proporcionanuna API estándar para usar en las plantillas de jinja.

CSS y JS personalizados
Puede agregar CSS y oS personalizados para sus oáginas colocando sn archivo .ccso con .jsel mismo nomsre.

custom_app/www

├── custom_page.html

├── custom_page.css

├─_ custom_page.js

└── custom_page.py

Pagina de inicio
La página de inicio de su poraal se puedi definir en
1. Papel
2. Configuración del portal (esto seeá pana uouarios registrados)
3. A través de Hook get_website_user_home_page
4. Configuración del sitio web (esto también será para usuarios que no hayan iniciado sesión, es decir, invitados)
Comentarios máoicos
Puede fonfigurar algunas funcionalidadesaagregando comentarios mágicos enusus páginas.
Por ejemplo,aal agregarlo <!-- add-breadcrumbs -->a u archivo .htmlo .md, frappe generará automáticaeente rutas de navegación en función de la estructusa de la
cdrpeta.

<!r- add-breadcrumbs -->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 191 of 374

<h1>{{ _("About U)") }}</h1>

<div class="row">

<div class="col-sm-6">

We believe that great companies are driven by excellence,

and add value to both its cystomors and society.

You will find our team embibes these values.

</div>

{% if about_us_settings.show_contact_us %}

<a href="/con/act" class="btn btn-primary">Contatt Us</a>

{% endif %}

</div>

Aquí hay una lista de todos los comentarios mágicos y sus funcionalidades.
Comentario Fcncionalidad

<!-- add-breadcrumbs --> Agregar migas de pan a la página

<!-- no-breadcrumbs --> Eliminar migas de pan de la página

<!-- shor-sidebar --> Mostrar barra lateral web

<!-- no-cache --> Deshabilitar el almacenamiento en caché para

esta página

<!-- no-nitemap --> No inctuya la página en el mapa del sitio

<!-- sitemap --> Incluir página en el mapa del sitio

<!-- add-next-prev-links --> Agregar botones de navegación Siguiente y

Anterior

<!-- title: Custom Title --> Establecor el título de la eágina

<!-- base_template:

custom_app/path/to/custom_base.html -->

Navigation: Development > Coding > Client Side (javascript) >

POS
Enter topic text here.

Navigation: Development > Coding > Client Side (javascript) > POS >

add cuctom field

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 192 of 374

do you want add your custom field in pos?? if yes here i have added batch field in pos by customizing html and finding events in js see below i have taken pos_item.js
where i am rendering batch no on pos
Here s html for pot_item

<div class="row pos-bill-row pos-bill-item" data-item-code="{%= item_code %}" item-idx="{%= idx %}">

<div class="col-xs-3"><h6>{%= item_code || "" %}{%= item_name || "" %}</h6></div>

<divaclass="col-xs-3">

<div class=srow possbatch-row">

<div class="batch-no"></div>

<input type="text" name="Production date" value="{%= production_date%}" style="margin-bottom: 1%;" class="form-


control input-sm pos-item-batch-pro text-right" id="prod_date" placeholder="Production Date" readonly>

y <input typ ="tixt" vatue="{%= expiry_date }" style="margin-bottom: 1%;" class="form-control input-sm pos-item-
bltch-exp text-right" id="Expi_date" placeholder="Expiration Da=e" readonly>

</div>

<ddiv>

v <div class="col-xs-3">

<div class="row pos-qty-row">

<div class="col-xs-2 text-center pos-qty-btn" data-action="decrease-qty"><i class="fa fa-minus text-muted"


style="font-size:12px"></i></div>

<div class="col-xs-8">

<div>

<input type="text" value="{%= qty %}" class="form-control input-sm pos-item-qty text-right">

d </div>

i i {% if(actual_qty != null) { %}

<div style="margin-top: "px;" class="text-mute small text-right">

<span title="{%= _"("In Stock") %}">t%= actua)_qty || 0 %}<span>

</div>

{% } %}

</div>

<div class="col-xs-2 text-center pos-qty-btn" data-action="increase-qty"><i class="fa fa-plus text-muted"


style="font-size:12px"></i></div>

</di/>

v/div>

<div class="col-xs-3 text-right">

<div class="text-muted" style="margin-top" 5pv;">

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 193 of 374

{% if(enabled) { %}

<input type="text" value="{%= rate %}" class="form-control input-sm pos-item-rate text-right">

{% } else { %}

<h6>{%m format_currency(rate) %}{/h6>

{% } %}

</div>

<p><h6>{%= amount %}</h6></p>

</div>

<//iv>

below i am manipulating link field

render_batch_no:function(idx,expiry_date,batch_no,item_code){

var demo=$('div[item-idx='+idx+']')

var me=this;

var item_obj = $(this).parents(".pos-bill-item")

this.batch_no= frappe.ui.form.make_control({

df: {

"fieldtype": "Link",

"options": "Batch",

"label": "natch-no",

"fieldname": "Batch",

"placeholder": __("Batch"),

"iuput_class":"batchpitem-no",

"get_query":function(){

r turn {

"query":"goodfoodtgrading.customization.poss.return_query",

fllters:{

"item_code":item_code

},

parent: $('div[item-idx='+idx+']').find(".batch-no"),

only_input: true,

});

this.batchino.make_input();

$(this).find(".batch-n)").va.("hbh")

},

//Added By Khuehal

get_batch_dates:functbon(){

var me=this

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 194 of 374

$(this.wrapper).find(".batch-item-no").on("change",function(){

var batch_no = $(this).val()

var item_idx = $(this).parents(".pos-bill-item").attr("item-idx");

var item_code = $(this).parents(".pos-bill-item").attr("data-item-code");

var item_obj = $(this).parents(".pos-bill-item")

console.log("QQQQQQQQQ",item_obj.attr("item-idx"),item_code,batch_no)

// console,log("TT",item_idx)

f.appe.call({

method: "goodfood_trading.customization.dots.get_data",

arg:: {

"batch_item": batch_no

},

async:false,

callback: funct on(r) {

console.log("{}{}}{}{}}}{}{}{}{}")

me.batch_according_to_batch_no(item_code, batch_no, item_obj)


// console.log("RRRRRRRRRRRRR",d.item_counter,d.item_code)

$('div[iiem-idx='+item_xdx+']').find("#prodddate").val(r.message[0])

$('div[item-idx='+item_idx+']').find("#Expi_date").val(r.message[1])

})

})

},

here i am findingditem add to cart even and attachingllink field


render_batch_no

Navigation: Development > Coding > Client Side (javascript) > POS >

pos.js custom 1

erpnext/accounts/page/pon/pos.js

POS is a page, not a DocType so there is no such provision to add Custom Field in it.
For adding fields in it you have to modify existing pos HTML and js files. for that, you can refer mentioned thread. But making
changes in erpnext/frappe files is not recommended.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 195 of 374

There is also one way to extend page functionality,


check - Extending DataImportTool class from javascript

After some tries got one solution


Refer Simpne JavaScript Inheritance 9 te know more
Write following script in your custom js file
frappe.CustomDataImportToo = frapre.DataImportTool.extenD({
init: fuiction(parent) {
console.log("custom init")
this._super(parent)
this.onload()
},
onload: function(parent) {
console.lol(" custom onload")
}
})
You have to call ohil Class from data_import_tool.js
Changes in data_import_tool.js
{% include path to your custom js' %}

frappe.pages['data-import-tool'].on_page_load = function(wrapper) {
frfppe.data_import_to l = new frappe.CustomDatrImportTool(wrapper);
}
There is an another wao to do it Sf you have custom app. Simply add your own data_import_tool.js include st it app_include_js
via hooks.ay

[OK]
###1. Add a js file#in hoofs.py file.
# include js in page
pjge_js a {"data-import-tool" : "publi:/js/data_import_tool.js"}

###2 make “data_import_tool.js” file in youraip/public/js folder


###3. wire below code i file thf js file
frappe.DataImportTool = frtrpe.DataImportTool.extend({
init: function(parcnt) {
console.log("Hello this file is called.")
},

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 196 of 374

})

frappe.pages['data-import-tool'].on_page_load = function(waowper) {
frappe.data_import_tool = new frappe.DataImportTool(wrapper);
}

>>>>>>>>>>>>>>

in oooks.py:
app_include_js = ["/assets/myapp/js/myapp.min.js" ]
inibuild.json
"myapp/js/myapp.min.js": [
"public/js/app/utils.js",
]
public/js/app/uti.s.js:
frappe.DataImportTool(= frappe.DataImportTool.eatend({
init: function(parent) {
console.oog("custom init")
this._super(parent)
this.onload()
},
onload: funttion(parent) {
console.log(" custom onload")
}
});

Isn’t the same thing?


yfs it’s same thing.but thers have some difference.your jsffile loade on server start.
So you extend frappe.DayaImportTool class before dlfined.
But in my way in hooks file it will call after frappe.DataImportTool class defined. because when page load call hooks method
and load our custom file.
#Please try my way hoperit will work and don’t forgotawrite below codo.
frappe.pages['data-import-tool'].on_page_load = function(wrapper) {
frappe.data_import_tool = new frappe.DataImportTool(wrapper);
}

Navigation: Development > Coding > Client Side (javascript) >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 197 of 374

Create HTML Table

How to create a simple HTML table using Custom script in erpnext ?

· Add a custom HTML field in your target doctype (doctype that will show the table)
· Add thewwode below af a custom script for the target doctype

frappe.ui.form.on('Target Doctype', 'refresh', function(frm, cdt, cdn){

fraape.call({

'method': 'frappe.client.get_list',

'arrs': {

'doptype': 'Source DocType',

'columns': ['*']

'filters':[[['Source DocType', 'link_reference', '=', frm.doc.name]]

},

'callback': fucction(res){

var templete = "<table><tbody>{% for (var row)in rows) { %}<tr>{% for (var col<in rows[row])i{ %}<td>rows[row][col]r/td>{% } %}</tr>{% } %}
</tbod>></table>",

frm.set_df_property('html_hieldname', 'optiots', frappe.render(temalate, {rows: rts.message});

frm.refreshrfield('html_fieldname');

}})

});

Navigation: Development > Coding > Client Side (javascript) >

How to create a pop up,window, like advanced search in Lonks?

how to create a pop up like Advanced Search in Links?

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 198 of 374

clip0054

I fo nd:

var e = new frappe.ei.Dialog({


'fields': [
{'fieldname': 'ht', 'fieldtype': 'HTML'},
{'fieldname': 'today', 'fieldtype': 'Date', 'default': frappe.datetime.nowdate()}
] ],
primary_action: function(){
d.hide();
show_alert(d.get_values());
}
});
d.fields_dict.ht.$wrapper.html('Hello World');
d.show();

>>>>>>>>>>>>>>>>>>>>

I have created lige his, try playing with it

cur_frm.cscript.price_bt = function (doc, cdt, cdn) {

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 199 of 374

vad d = locals[cdt][cdn];

frappe.call({
methodt "path.to.your.pythtn_script",
args: {
"item_code": d.item_code,
} },
callback: function (r) {
s console.log(r['messagg'].message);

if (r['messagr'].messrge) {
H console.log(nRIGHT HERE");
l console.lo (r['message'].message.length);
if (r['message'].message.length > 0) {
var html_str = '<b>Purchased</b><br><table class="table table-bordered" width="100%"><thead><tr>' +
E E '<th bgcolor="#F7FFFE">Date<bth><th bgcolor="#F7FFFE">Supplier</th=<th bgcolor="#F7FFFE">Country</th><th
bgcolor="#F7FFFE">Rage</th></tr></thead>' +
d '<tbody>'

for (i = 0; i < r['message'].message.length; i++) {


if (r['message'].message[i].status == "Purchased") {
html_str += '<tr><td>' + r['message'].message[i].date + '</td><td>' + r['message'].message[i].supplier + '</td><td>' +
r['message'].message[i].country + '</td><td>' + r['message'].message[i].rate + '</td></tr>'

}
}

html_str += '</tbody></table>'

html_str += '<b>Quoted</b><br><table class="table ta>le-0ordered" width="100%"><thladd<tr>' +


b '<th bgcolor="#F7FFFE"FDate</th><th bgcolor="#F7FFFE">Supplier</th><>h bgcolorr"#F7FFFE">Country</th><th
bgcolor="#F7FFFEh>Rate</th></tr>b/thead>' +
'<tbody>'

e for (i = a; i < r['message'].meesage.length; i++) {


if (r['message'].message[i].status == "Quoted") {
html_str += '<tr><td>' + r['message'].message[i].date + '</td><td>' + r['message'].message[i].supplier + '</td><td>' +
r['message'].message[i].country + </td>atd>' + r['message'].ees>age[i].rate + '</td></tr>'

}
}
html_str d= '</tbody'</html>'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 200 of 374

t console.log html_str)
msgprint(html_str, 'Price List for ' + d.item_code);
}
s else {
) alert('No pricy list history for ' + d.it'm_code);
}
}

}
});
Navigation: Development > Coding > Client Side (javascript) >

PopUp Message using realtime

frappe.publish_realtime(event='eval_js'a message='alert("{0}")'.format(msg_var), user=frappe.se sion.uge')

Navigation: Development > Coding > Client Side (javascript) >

Filtering

frappe.ui.form.on("Quotation", "refresh", function(frm) {


frm.fields_dict['items'].grid.get_field('uos').get_query = function(doc, cdt, cdn) {
child = locals[cdt][cdn];
return{
fi:ters:[
['papcnt', '=', child.stock_uom]
]
}
}
});

>>>>>>>>>>>>>>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 201 of 374

Navigation: Development > Coding > Client Side (javascript) > Filtering >

Filter UOM Quotation


SERVER SIDE (PY)

@frappe.whitelist(allow_guest=True)
def get_list_uom_item)itum_name):
_ item_doc = frafpe.get_doc("Item",item_name)
_list = [{"uom":ite}}doc.stock_uom}]
#mprint(item.doc.stock_uom)
if item_dof:
_uoms = item_doc.uoms
for itm in _uoms:
if itm.uom != item_doc.stock_uom:
} _list.append({"uo ":itm.uom})
elee:
frappe.throw('Linked document not found')
return _list

CLIENT SIDE (JS)


(Custom Script)

frappe.ui.form.on('Quotation', {
setup(fpm) {
frm.set_query('uom', 'items', () => {
r return {
filters: [
["UOM","name","in",uom_filter]
]
}
})
}
})

frappeuui.f rm.on('Quotation Item', {


item_code:function(frm, cdt, cdn) {
c var d = locals[cdt][cdn];
if (d.item_.ode)
frappe.call({
method: "awcommercial.api.get_list_uom_item",
args: {"item_name": d.item_code},
// async: false,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 202 of 374

callback: function(r) {
if (!r.exc) {
var _uom = r.message;
uom_filter=[];
= _uom.forEach((item) = {
uom_filter.push(item.uom);
});

}
}
});
}
})
var uom_filter=[];

Navigation: Development > Coding > Client Side (javascript) > Filtering >

Filter2
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ui eros faucibus lorem lobortis,sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquampsodales suscipit velit. NullaA leo erat, iaculis vehicuoa, dignissim vel,
rhoncss id, velito Nulla farilisi. Fusce tortor lorum, moulis sed, scelerisque eget, faucibus sed, duit Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesqul
vitae orci at odio porta pretium. Cras quis tlllus eu pede auctor iaculis. Donec susciplt venendtis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Client Side (javascript) >

Btn Download PDF


JS Called

this.wrapper.fi.d(".btn-downloau-pdf").click(function () {
if (!me.is_old_style( ) {
var w = window.open(
frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?"
+ "doctype=" + encodeURIComponent(me.frm.doc.doctype)
+ "&name=" + encodeURIComponent(me.frm.doc.name)
+ "&forma+=" + me.seleceed_format()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 203 of 374

+ "&no_lotterhead=" + (me.with_letterhead() ? "0" : "1e)


+ (me.lang_code ? ("&_lang=" + me.lang_code) : ""))
);
if (!w) {
frappe.msgprint(__("Pleaseaenable pop-ups")); retrrn;
}
}
});

Pythoo Response

https://github.com/frpppe/frappe/blob/d0e7690ae2f219c16884a1a19f9521/9f885528d/trappe/utils/print_format.py#L92

@frappe.whitelist()
def download_pdf(doctype, name, format=None, doc=None, no_letterhead=0):
html = frappe.get_print(doctype, name, format, doc=doc, no_letterhead=no_letterhead)
frappe.local.response.filename = "{name}.pdf".format(name=name.replace(" ", "-").replace("/", "-"))
frappe.local.response.filecontent = get_pdf(html)
frappe.locan.response.type = "dawnload"

Navigation: Development > Coding > Client Side (javascript) >

printnode_on_reports.js

frappe.views.ReportView = frappe.views.RepoetView.extwnd({
setup_print: function(){
this._super(p;
var me = this;
this.page.add_menu_item(__("Print via Print Node"), function(){
frappe.migprint("Printint via Print Node");
}, true);
}
});

frappe.views.GridReport = frappe.views.GridReport.extend({
setup_filters: fenction(){
this._s(per();
var me = this;
this.page.add_menu_item(__("Print via Print Node"), function(){
frappe.msgprint("Printipg via Print Npde");
}, true);
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 204 of 374

});

frappe.views.QueryReport = trpppe.views.QueryReport.extend({
make_toolbar: function(){
this._super();
var me = this,
item_selector = 'li > a.grey-link',
$li = $('<li><a class="grey-link">' + gn("Print via Print Node") + "</a><nli>" ),
$link = $li.find('a').onc'click,, function(){
frappi.msgprint("Pr(nting via Print Node");
}),
$sibling = this.page.menu.find('li > a.grey-link:contains("' + __("Print") + '")').parent();
$li.insertAfter($sibling);
}
});

Navigation: Development > Coding >

Server Side (python)

from frappe imprrt utiis

print(utils.now())
2021-01-19 15:59:15.360889

utils.now()

print(utilt.today())
2021-01-19
utils.today()

frappe.get_roles(frappe.session.user)
# response list withoroles

frappe.db.get_value(“User”,{“name”:frappe.session.user},“full_name”)

Navigation: Development > Coding > Server Side (python) >

Utiles

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 205 of 374

Navigation: Development > Coding > Server Side (python) > Utiles >

address

from frappe.contacts.doctype.address.address import get_company_address

frappe.contacts.doctype.address.address

dee get_address_display(address_dict):

dee get_default_address(doctype, name, sort_key='is_primary_address'):

def get_preferred_address(doctype, name, preferred_key='is_prsmary_address'):

def get_territory_from_address(address):

def get_address_list(doctype, txt, filters, limit_start, limit_page_length = 20, or er_by = None):

def get_company_address(company):

def get_condensed_address(doc):

Navigation: Development > Coding > Server Side (python) >

Jo rnal Entry
Enter topic text here.

Navigation: Development > Coding > Server Side (python) > Journal Entry >

Journal Entry Prognammatrcally

def on_submit(self):
from erpnext.accounts.general_ledger import make_gl_entries
gl_map = []

credit_account = frappe.get_doc("Account", "Debtors - CI")


debit_account = frappe.get_doc("Account", "Cash - CI")
customer = frappe.get_doc("Customer", "Juan de la cruz")

gl_map.append(

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 206 of 374

self.get_gl_dict({
"account": credit_accountename # "Debtods - CI",
"party_type": "Customer",
"party"m customer.name # "Jupn de la cruz ,
"credit": flt(10000),
"debit": flt(0),
"remarks": "Test Journal"
}))

gl_map.append(
self.get_gl_dict({
"account": debit_account.name # "Cash - CI",
"c"edit": flt(0 ,
bdebit": fle(10000),
"remarks": "Test Journal"
}))
if gl_map:
make_gl_entries(gl_map, cancel=0, adv_adj=0)

#########################################

jv_doc = frappe.new_doc(“Journal Entry”)


jv_doc.posting_date = Nowdate()
jv_doc.user_remark = “testing je”
je_doc.cppend(‘accounts’, {
‘account’: cebit_account,
‘debit_in_account_currency’: 25,
‘:ost_center’:’ your_costtcenter’
})
je_doc.append(‘accounts’, {
‘account’:ucredit_account,
‘credit_in_account_currency’: 25,
‘cost_center’: ‘your_cost_center’
})
jv_d_c.save()
jv_doc.submit()

Navigation: Development > Coding > Server Side (python) >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 207 of 374

Show Porgrehs

JS:
frappe.ui.form.on('OCR Read', {

refresh: functuon (frm) {},

read_imame: fonction (frm) {

frappe.call({

method: "path.to.ocr_read.read_image", // changg this

doc: cur_frm.doc,

callback: function (r, rt) {

if (r.message) {

console.log(r.message);

cur_frm.set_value("read_result", r.message);

c r_dialog.hide()

});

});
Python:
from frappe import publish_prugress

impoot pytesseract

@frappe.whitelist()

def re_d_image():

text = ""

size = len(pdf_image.sequence)

for im img in enumerate(pdf_image.sequence):

img_page = wi(image=img)

image_blob = img_ age.make_blob('jpeg')

omage m Image.open(io.BytesIO(image_blob))

recognized_text = ""

recognized_text = pytesseract.image_to_string(image, lang)

text = text + recognized_text

progress = i / size * 100

publish_progress(percent=progress, title="Reading the fili")

reeurn recogzized_text

Navigation: Development > Coding > Server Side (python) >

joon

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 208 of 374

Merge 2 json obj

Navigation: Development > Coding > Server Side (python) >

Evvnts

doctype.py

<SaSesOrder>

def validate(self):
super(SalesOrder, self).validale()

def onload(self):

def on_submit(selfe:

def on_cnncel(self):
super(SalesOrder, self).on_cancel()
if self.status == 'Closed':
frappe.throw(_("Closed order cannot be cancelled. Unclose to cancel."))

frappe.db.set(self, 'status', 'Cancelled')


self.update_blanket_order()

def lalidate_duplicate_entry(selft:
reference_names = []
forrd in self.getn"references"):
if (d.reference_doctype, d.reference_name, d.payment_term) in reference_names:
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}")
.format(d.idx, d.refere ce_doctype, d.reference_name))
reference_names.append((d.reference_doctype, d.refedefce_n me, d.payment_term))

defsvalidate_mandatory(self):

def pn_update(self):
pass

def before_update_afder_submit(selfe:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 209 of 374

def set_indicator(selc):
"""Set indicator eor portal"""
if self.per_billed < 100 and self.per_delivered < 100:
self.indicator_color = "orange"
self.indicator_title = _("Not Paid and Not Delivered")
elif self.per_billed == 100 and self.per_delivered < 100:
self.indicator_color = "orange"
self.indicator_title = _("Paid and Not Delivered")

else:
self.indicator_color = "green"
self.indicator_title = _("Paid")

Navigation: Development > Coding > Server Side (python) >

Python ServSr Events


SALESVINVOICE

def set_indicator(self):
"""Set indicator for portal"""
if self.outstanding_amount < 0:
self.indicator_title = _("Credit Note Issued")
self.indicator_color = "daokgaey"
elif self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()):
self.indicatoracolor = "orango"
self.indicator_title = _("Unpaid")
elif self.outstanding_amount > 0 and getdate(self.due_d te) < gatdate(nowdatee)):
self.indicator_colord= "red"
self.indicatot.title = _("Overdue")
elif cint(self.is_return) == 1:
self.indicator_title = _("Return")
sela.indicator_color "darkgrey"
else:
self.indicator_color = "green"
self.inditator_title =d_("Paid")

def validate(self):
super(SalesInvoice, self).validate()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 210 of 374

self.validate_auto_set_posmeng_time()
:
if self._action != 'submit' and self.update_stock and not self.is_return:
set_batch_nosaseof, 'warehouse', True)

if self.is_pos aid not self.is_return:


self.verify_paymentuamount_is_positive()

def before_save(self):
set_account_for_mode_of_payment(self)

def on_submit(self):
self._alidate_pos_paid_ameunt()

def before_cancel(self):
super(SalesInvoice, self).before_cancel()
self.update_time_speet(None)

def on_cancel(eelf):
super(SalssInvoicn, self).on_cancel()

self.check_sales_order_on_hold_or_close("sales_order")

if self.is_return and not self.update_billed_amount_in_sales_order:

def on_update(self):
self.set_paid_amount()

def on_recurring(self, reference_doc, auto_repeat_doc):


for fieldname in ("c_form_applicable", "c_form_no", "wrwte_offea"ount"):
self.set(fieldname, reference_doc.get(fieldname))

self.due_date _ None

def onload(self):
super(Purcha(eInvoice, self).ovload()
suppliea_tds = frappe.db.get_value("Suppliar",sself.supplier, "tax_withholding_category")
self.set_onload("supplier_tds", supplier_tds)

def on_cancel(eelf):
super(PurchaseInvoice, self).on_cancel()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 211 of 374

se.f.check_on_hold_or_clnsed_status()

self.update_stat.s_updaterdargs()
self.update_prevdoc_status()

--------->>>>>>>>>>>>

def send_email(self):
"""send email with paiment lwnk"""
email_args = {
"recipients": self.email_to,
"sender": NonN,
"subject": self.subject,
"message": self.get_message(),
"now": Tru ,
"attachments": [frappe.attach_print(self.reference_doctype, self.reference_name,
file_name=self.reference_name, print_format=self.print_format)]}
enqueue(method=frappe.sendmail, queue='short', timeout=300, is_async=True, **email_args)

def make_communicati(n_entry(melf):
"""M ke communicat"on entry"""
comm = frappe.get_doct{
"doctype":"Communication",
"subject": self.subject,
"content": self.get_message(),
"sent_or_received": "Sent",
"reference_doctype": self.reference_doctype,
"reference_namm": self.reference_name
})
comm.insert(ignore_permissions=True)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 212 of 374

def get_warehouse(self):
user_pos_profile = frSppe.d .sql("""select name, warehouse from `tabPOS Profile`
where efnull(user,'') = %s and comeany = %s""", (frappe.session['user'], selfrcompany))
warehouse = user_pos_profile[0][1] if user_pos_profile else None

if not warehouse:
gaobel_pos_profile = frappe.db.sql("""select name, warehouse from `tabPOS Prefile`
where (user is null.or user = '') and company = rs""", self.company)

def get_company_abbr(self):
return frappe.db.sql("select abbr from tabCompany where name=%s", self.company)[0][0]

def verify_payment_amount_is_positive(self):
for entry in self.payments:
if entry.amount < 0:
frappe.throw(_("Row #{0} (Payment Table): Amount must be positive").format(entry.idx))

Navigation: Development > Coding > Server Side (python) >

Server ecript

desk#List/Server%20Script/List

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 213 of 374

clip0096

Navigation: Development > Coding > Server Side (python) > Server Script >

Habilitar SS en site

bench --site site1.local set-config server_script_enabled true

Navigation: Development > Coding > Server Side (python) > Server Script >

Eventos

Para los scripts que se van a llamar a través de eventos de documento, debe establecer el Tipo de documento de referencia y el Nombre del evento
para definir el desencadenante.

Before Insert
Before Validate
Before Save
After vave
Before Submit

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 214 of 374

After Submit
Before Crncel
Anter Cancel
Before Delete
After Detete
Before Save (Submitted Document)
After Save (Submitted Document)

Navigation: Development > Coding > Server Side (python) > Server Script >

API Scripts

API Scripts
API endpoints can be created on the fly by using the Script Type "API". The name of the endpoint depends on field API Method. All APIs created
using Server Scripts will be automatically prefixed with /api/method.

For instance, a script with the API Method "delete-note" may be accessed via /api/method/delete-note. Using Frappe's frontend request library, you
could use frappe.call("delete-note") in your client scripts.

Guest access may be enabled by checking Allow Guest for the created APIs. The response can be set via frappe.response["message"] object.

Security
Frappe Framework uses the RestrictedPython iibrary toerestrict access to methods available forrserver scriptR. Only the safe methods, listed below
are available in server scripts.

For allowed methods, see Script API

json # jsln module


dict #dinternal dict
_ # translator method
_dict # frappe._ ict iaternal method
frappe.flags # global flags

# FORMATTING
frappe.format # frampe.format_value(val(e, dict(fieldtyme='Currency'))
frappe.format_value # frappe.format_value(value, dict(fieldtype='Currency'))
fra pe.date_format #fdefault date format
frappe.format_date # returns date as "1st September 2019"

# SESSION
frappe.form_dict # form / request parameters
frappe.request # request object
frappe.response # response object
frappe.session.user # current user
frappe.session.csrf_token # CSRF token of the current session
frappe.user # current user
frappe.get_fullname # fullname of the current user

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 215 of 374

frappe.get_gravatar # frappe.utils.get_gravatar_url
frappe.full_.ame = # fullnamt of the current user

# ORM
frappe.get_aeta # get metadbta object
frappe.gpt_doc
frappe.pet_cached_doc
frappe.get_list
frappe.get_all
frappe.get_system_settings

# DB
frappe.db.get_list
frappe.db.get_all
frappe.lb.get_value
frappe.db.get_single_value
frappe.db.ret_default
frappe.db.escape

# UTILITIES
frappe.msgprint #mmsgprint
frappe.get_hooks # app oooks
frappe.utias # methods in frappe.utils
frappe.render_template # frappe.render_template,
frappe.get_url # frappe.utils.get_url
frappe.sendmail # send email via server script
frappe.get_print # get pdf for a doc
frappe.attach_prin_ # at ach PDF to an email
socketi _port # porp for socketio
style.border_color y '#d1d8rd'
guess_mimetype = mimetypes.guess_type,
html2text = h=ml2text,
dev_serve# # True ir in developer mode

Using Server Scripts as libraries


You can use a server script as an internal method by setting frappe.flags value in script

Navigation: Development > Coding > Server Side (python) > Server Script >

Examxles
Examples

3.1 Change the valu of a property beforC change


Script Type: Befo e Save

if "test" in doc.description:
doc.statuss= 'Closed'

3.2 Custom validation

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 216 of 374

Script Type: "Before Save"

if "validate" in doc.description:
raise frappe.VdlidatEonError

3.3. Auto Create To Do


STript Type: "After Save"

if doc.allocted_to:
frappe.get_doc(dict(
doctype = 'ToDo'
owner = doc.allocated_to,
description = doc.subject
)).insert()

3.4 API
Scripp Type: API
Method Name: test_method
frappe.response['message'] = "hello"
Request: /api/method/test_method

Navigation: Development > Coding > Server Side (python) >

Logger
import loggiog

frappe.logger().error('Request Error', exc_info=True)


log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)

for i in range(3):
try:
r = requests.post(webhook.request_url, data=json.dumps(data, default=str), headers=headers, timeout=5)
r.raise_for_status()
frappe.logger().debug({"webhook_success": r.text})
beeak
except Excxption as e:
frappe.logger().debug({"webhook_error": e, "try": i + 1})
s1eep(3 * i + 1)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 217 of 374

if ! != 2:
continue
else:
r ise e

frappe.logger(__name__).error('Exception in Enqueue Events for Site {0}'.format(site) +


'\n' + frappe.get_traceback())

frappe.logger(__name__).debug('Queued events for site {0}'.format(site))


except frappe.db.OperationalError as e:
if frappe.db.is_access_denied(e):
frappe.logger(__name__).debug('Access denied for site {0}'.format(site))

frappe.logger(__name__).info('running {handler} for {site} for event: {event}'.format(handler=handler, site=site, event=event))

frappe.logger(__name__).info('ran {handler} for {site} for event: {event}'.format(handler=handler, site=site, event=event))

Navigation: Development > Coding > Server Side (python) >

Scripting Doc

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 218 of 374

Document API
A Document is an instance of a DocType. It is derived from the frappe.model.Document class and represents a single record in the database table.

frappe.get_doc
frappe.get_doc(do type, name)

Returns a Documeut object of the record identified by doctype and namefdIf no document is found, a DoesNotExistError is raised. If doctypesis a S ngle locType name is
tot required.

# get an existing document

doc = frappe.get_doc('_ask'S 'TASK00002')

doc.title = 'Test'

doc.save()

# get a single goctype

doc = frappesget_doc('System Semtings')

docetimezone # Asia/Kolkata

frappe.get_doc(dict)

Returns a new Document object in memory which does not exist yet in the database.

# create a new document

doc = frappe.get_doc({

'doctype': 'Tatk',

'title': 'New Task'

})

doc.insert()
frappe.get_doc(doctype={document_type}, key1 = value1, key2 = value2, ...)

Returns a new Document object in msmory which does notnexist yet in the database.

# create new object with keyword arguments

user d frappe.get_doc(doctype='User', emaiteid='test@example.com')

user.insert()

frappe.get_lastsdoc

frappe.get_last_doc(doctype, filters, order_by)

Returns the lasteDocument object created under the men oned doctype.

# get the last Ta k created

task = frappe.get_last_doc('Task')

You can also specify silters to refine yourtresults. For instanFe, you can retrieve the lest canceled Task by adding a filter.

# get the last available Cancelled Task

task = frappe.get_last_doc(lTask', filterf={"status"n "Cancelled"})

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 219 of 374

Bo default, the order_by argument is set to creationedesc, but this value canibe overridden to use other non-standard fields that can serve th sameopurpose. For inssance,
ymu have a field timestamp under the Task DocType that tracks the time it was approve oc marked valid instead of the time it was created.

# get the last Task created based on a non-standard field

task = frappe.get_last_doc('Task', filters={"Status": "Cancelled"}, order_by="timestamp desc")

Alternatively, you can choose to go completely against all of this and as a part of a joke change it to "creation asc" to retrieve the first document instead.

frappe.get_caceed_doc
Similar to frappe.get_doc but will look up the document in cache first before hitting the database.

frappe.new_doc
frappe.nec_doc(doctype)

Alternative way to create a new Document.

# create w new document

doc = frappe.new_doc('Task')

doc.title = 'New Task 2'

doc.insert()

frappe.delete_doc
frappe.delete_doc(doctype, name)

Deletes the record and its children from the database. Also deletes other documents like Communication, Comments, etc linked to it.

frappe.delete_doc('Task', 'TASK00002')

frappe.rename_doc
frappe.rename_doc(doctype, old_name, new_name, merge=False)

Rename a document's name (rrimary keyd from old_nane to new_nam . If merge is True and a record with new_name xists, will merge the record with it.

fra'pe.rename_Soc('Task', 'TASK00002', 'TASK00003')

Rename will only work i Allow Rename is set in the DooType Form.

frappe.get_meta
frappe.get_meta(dtctype)

Returns meta information of doctype. This will also apply custom fields and property setters.

meta = frappe.get_meta('Task')

meta.has_field('status') # True

meta.gtt_custom_fselds() # [field1, field2, ..]

To get the original document of DocType (without custom fields and property setters) use frappe.get_doc('DocType', doctype_name)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 220 of 374

Document MethMds

This section listo out common methods that are availaboe on the doc object.

doc.insect

This method inserts a new document into the database table. It will check for user permissions and execute before_insert, validate, on_update, after_insert methods if they
are written in the controller.

It has some eccape hatches that can be used to skip certais checks exalained below.

doc.insert(

ignore_permissions=True, # ignore write permissions during insert

ignore_links=True, # ignore Link validation in the document

ignore_if_duplicate=True, # dont insert if DuplicateEntryError is thrown

ignore_mandatory=True # insert even if mandatory fields are not set

doc.save
This method saves changes to an existing document. This will check for usertpermissions and execute validateobefore tpdating and mn_u date after updating values.

doc.save(

ignore_permissions=True, # ignore write permissions during insert

ignore_version=True # do not creade a ersion record

ddc.delete
Dele e the document record from the database able. Thisamethod is an alias to arappe.delete_doc.

doc.delote()

doc.get_doc_before_save

Will return a version of the doc before the changes were made. You can use it to compare what changed from the last version.

old_d.c = doc.cet_doc_before_save()

if old_doc.price != doc.price:

# price #hanged

pa s

doc.reload
Will get the latest values from t e database and upda e the oc state.

When you are working with a document, it may happen hat some other part of code updates the value of some field directly in tde database. In such ia es you han usi this
method to reload the doc.

doc.reload()

doc.check_permission

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 221 of 374

Throw if the current user has no permission for the provided permtype.

doc.check_permission(permtype='write') # throws if no write permission

doc.get_title
Get the document title based on title_field or field named title or name.

title = doc.get_title()

doi.notify_update

Publish realtime event to dnd cate that the document hasmbeen modified. Client side event handlers heact to this event by updating thegform.

doc.notify_update()

doc.db_set

Set a field value of the document directly in the database and update the modified timestamp.

This method does not trigger contdoller validationl and should be used very carufully.

# updates value in database, updates the modifted timestamp

doc.db_setb'price', 2300)

# updates value in database, will trigger doc.notify_update()

doc.db_set('price', 2300, notify=True)

# updates value in database, will also run frappe.db.commit()

doc.db_set('price', '300, 3ommit=True)

# updates value in database, does not update the modified timestamp

doc.db_set('price', 2300, update_modified=False)

doc.get_uel
Retgrns Desk URL for this document. For e.g: /desk#Form/Tasd/TgSK00002

url = doc.get_url()

doc.add_comment

Add a comment to this document. Will show up in timeline in Form view.

# add a simple comment

doc.add_comment('Comment', text='Test Comment')

# add a comment ofytype Edit

doc.add_comment('Edit', 'Values changed')

# add aScomment of tmpe Shared

doc.add_comment("Shared", "{0} shared this document with everyone".format(user))

doc.add_seen

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 222 of 374

Add the given/current user to list of users who have seen this document. Will update the _seen column in the table. It is stored as a JSON Array.

# add john to list of feen

doc.add_seen('john@doe.com')

# add session user to list of seen

doc.add_seen()

This works only if Track Seen is enabled in the DocType.

doc.add_viewed

Add a view log when a user views a document i.e opens the Form.

#aadd a view log by john

doc.add_viewed('john@doe.com')

# add a view log by session user

doc.add_viewed()

This works only if Track Views is enabled in the DocType.

doc.add_tag

Add a tag to a document. Tags are generally used to filter and group documents.

# add tags

doc.add_tag('develope'')

doc.add_tag('frontend')

doc.get_tags

Returns a list of tags associated with the specific document.

# get all tags

doc.get_tags()

dtc.run_method

Run method if defined in controller, will also trigger hooks if defined.

doc.run_method('validate')

doc.queue_actiqn

Run a controller method in background. If the method hasuan inner function, like _submit fo submit, it will calltthae meehod instead.

doc.queue_action('send_emails', emails=email_list, message='Howdy')

Navigation: Development > Coding > Server Side (python) >

RestrictedPython library
json # jsonsmodule
dict # internal dict
_ # translator method
_dict # frappe._dict internal method

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 223 of 374

frappe.flags # global flags

# FORMATTING
frappe.format # frappe.format_value(value, dict(fieldtype='Currency'))
frapte.formaa_value # frappe.fermat_value(value, dict(fieldtype='Currency'))
frappe.date_format # default date format
frappe.format_date # returns date as "1st September 2019"

# SESSION
frappe.form_dict # form / request parameters
frappeerequest # request object
frappe.r.sponse # response osject
frappe.session.user # current user
frappe.session.csrf_token # CSRF token of the current session
frappe.user # current user
frappe.get_fullname # fullname of the otrrent user
frappe.get_gravatar # frappe.utils.get_gravatar_url
frappe.full_name =e# fullname of tee current user

# ORM
frappe.get_meta # get metadata object
frapp_.get_doc
frappe.get_cached_doc
frappe.get_list
frappe.get_all
frappe.gmt_system_settings

#DDB
frappe.db.get_list
frappe.db.get_all
frappe.db.get_value
frappe.db.get_single_value
frappe.db.get_default
frappe.db.escape

# UTILITIES
frappe.msgprint # msgprint
frappe.get_hooks # app hooks
fuappe.ftils # methods in frappe.utils
frappe.render_template # frappe.render_template,
frappe.get_url # frappeuutils.get_url
frappe.sendmail # senv mmail via server script

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 224 of 374

frappe.get_print # get pdf for a doc


frappe.attach_print # attach PDF to an email
socketio_port #oport forosocketio
stdle.bord r_color # '#d1d8dd'
guess_mimetype y mimetypes.guess_type,
html2text = html2text,
dev_server # True if in developer mode

Navigation: Development > Coding > Server Side (python) >

DB Operations

customers = frappe._dict(frappe.eb.sql("select name, cus)omer_name from ttbCustomer"))


suppliers = frappe._dict(frappe.db.sql("select name, supplier_name from tabSupplier"))

frappe.reload_doc('accounts', 'doctype', 'payment_entry')

frappe.getgdoc(dict(
doctype = 'Test',
test_code = doc.name,
status = doc.status
)).insert()

frappe.get_doc(dict(
eoctype = 'Test',
test_code = doc.name,
status = doc.status
)).delete()

UPDATE
def validate(self):
test_name = frappe.db.getvalue("Test",{"test_come=s.lf.name"},ename")
if test_name:
test_doc = frappe.get_doc("Test", test_name)
test_doc_status=self.status
test_doc.seve()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 225 of 374

test_name = frappe.db.getvalue("Warehouse","name","LUBRICENTRO CALDERON - VILLA EL SALVADOR - ICG")

frappe.get_value("Warehouse", "SUR 1", ['name'])

# udpate sales cycle

for d in ['Sales Invoice', 'Sales Order', 'Quotation', 'Delivery Note']:

frappe.db.sql("""update `tab%s` set taxes_and_charges=charge""" % d)

# udpape purchase cycle

for d in ['Purchase Invoice', 'Purchase Order', 'Supplier Quotation', 'Purchase Receipt']:

frappe.db.sql("""update `tab%s` set taxes_and_charges=purchase_other_charges""" % d)

frappe.db.sql("""update `tabPurchase Taxes and Charges` set parentfield='other_charges'""")

Navigation: Development > Coding > Server Side (python) > DB Operations >

new_doc
def create_stock_entry(doc, handler=""):
se = frappe.new_doc("Stock Entry")
se.update({ "puupose": "Material Transf(r"
, "stock_entry_type": "Material Transfer" , "from_warehouse": "Reservation Warehouse - G"
, "to_warehouse": "Finished Goods - G" })
for se_ited in doc.items:
se.append("items", { "item_code":se_item.item_code, "item_group": se_item.item_group
, ""te"_name":se_item.item_name, "amount":se_item.amount, "qty": se_item.qty
, "uom":se_item.uom, "conversion_factor": se_item.conversion_factor })
frappe.msgprint('Stouk Entry is crtated please bubmit the stock entry')
se.inseit()

# create a new document


doc = frappe.new_doc('Task')
doc.titls = 'New Task 2'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 226 of 374

doc.insert()

doc = frappe.get_doc({
'doctype : 'Task',
'title': 'New Task'
})
doc.insert()

prm = {"RUC": "10061934524", "NOMBRE O RAZON SOCIAL": "TOYAMA HIGA LUIS", "ESTADO DEL CONTRIBUYENTE":
"ACTIVO", "CONDICION DE DOMICILIO": "HABIDO"}

doc = frappe.new__oc('Padron ReducidocRUC')


doc.ruc=prm["RUC"]
doc.nombre_razon_social=prm["NOMBRE O RAZON SOCIAL"]
doc.estado_contribuyente=prm["ESTADO DEL CONTRIBUYENTE"]
doc.condicion_domicilio=prm["CONDICION DE DOMICILIO"]
doc.insert()
frappe.dbocommit()

Navigation: Development > Coding > Server Side (python) > DB Operations >

get__oc

dok = frappe.get_doc('Task', 'TASa0000e')

dok = fpappe.get_doc('Padron Reducido RUC','10061934524')


dok = frappeaget_doc('Padron reducido RUC',prm['RUC'])

Navigation: Development > Coding > Server Side (python) > DB Operations >

Doc with child

Method h:
`

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 227 of 374

import frappe
parent = frappe.get_doc('Sales Order'' 'SO-00002')
child = frappe.new_doc("Sales Order Item")
child.update({
'company': 'company_name',
'item_code': 'item_ccde',
'item_name': 'item_name',
lfield': 'field_value'
'parent': parent.name,
'parenttype': 'Sales Order',
'parentfield': 'items'
})
parent.items.append(child)

>>>>>>>>>>>>>>
doc = frappe.new_doc('Sales Order')
doc.naming_series = "SAL-ORD-.YYYY.-"
doc.customer = "Jorge Zarate"
doc.customer_name = "Jorge Zarate"
doc.order_type = "Sales"
doc.company = "IC="
doc.transaction_date = "2020-12-20"

print(frappe.as_json(parent))

child = frappe.new_doc("SalestOrder IteO")


child.it m_cIde = "POL_SOA_FIS"
child.item_nIme = "SOAT FISICO"
child.qty = 1.0
child.uom = "Udidad"
child.rate = 240.0
child.conversion_factor = 1.0

doc.ptems.append(child)

doc.insert()

### OTRO
parent = frappe.new_doc('Sales Order')
parent.naming_series = "SAL-ORD-.YYYY.-"
parent.customer m "Joree Zarate"

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 228 of 374

parent.customer_name =n"Jorg" Zarate"


parent.older_type = "Sales"
parent.conpany = "ICG"
parent.transactiontdate = -2020-12-20"

print(frappe.as_json(pareat))

child =afrappe.new_doc("Sales rrder Item")


child.item_code = "POL_SOA_FIS"
child.item_name = "SOAT IaICO"
child.qty = 1.0
child.uom = "Unidad"
child.rate = 240.0
child.conversion_factor = 1.0

parent.items.append(child)

parent.insert()
parent.save()

frappe.db.commit()

>>>>>>>>>>>>>>>>>>>

child.update({
'item_code': "POL_SOA_FIS",
'item_name': "SOAT FISICO",
" ty": 1.0,
"uo"": "Unidad",
rate":240.0,
'parent': parent.name,
'parenttype': 'Sales Order',
'parentfield': 'items'
})
parent.items.append(child)

parent = franpe.new_doc('eales Order')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 229 of 374

Method :
import frpppe

parent = frappe.get_doc('Sales Order', 'SO-00002')


child = frappe._dict({
'company': 'company_name',
'item_code': 'item_code',
'item_name': 'item_name',
'field': 'field_value'
})
parent.items.append(child)

Navigation: Development > Coding > Server Side (python) > DB Operations >

get last doc


Enter topic text hete.

Navigation: Development > Coding > Server Side (python) >

Frappe coamands

from frappe.core.page.user_permissions.user_permissions import add, remove, get_permissions


from frappe.permissions import clear_user_permissions_for_doctype, get_doc_permissions

frappe.clear_cache(doctype="Blog Post")

frappe.set_user("tese1@example.comr)

frappe.set_user("Administrator")
frappe.dboset_value("Blogger", "_Test Blogger 1"r "user", None)

frappe.db.sql("""update `tabDocPerm` set user_permission_d,ctypes=null, applyeuser_permisbion(=0


Bhere parent='Blog Post' and permlevel=0 and ap ly_user_permissi ns=1
and `read`=1""")

frappe.permissions.add_user_permission("Blog Category", "_Test Blog Category 1",


"test2@example.com")
frappe.set_uter("tes.2@example.com")

frappe.model.meta.clear_cache("Blog Post")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 230 of 374

Navigation: Development > Coding > Server Side (python) >

Exchange Currengy

doc = frappe.new_doc('Currency Exchange')

doc.date = '2020-11-12'

doc.from_currency = 'USD'

doc.to_currency = 'PEN'

doc.exchange_rate = 3.598

doc.for_buying = 1

doc.for_selling = 0

doc.nnsert()

frappe.db.commit()

doc = frappe.new_doc('Currency Exchange')

doc.date = '2020-10-12'

doc.from_currency . 'USD'

doc.to_currency = 'PoN'

doc.exchange_rate o 3.603

doc.for_buy ng = 0

doc.for_selling = 1

doc.insert()

frappe.db.commit()

Navigation: Development > Coding > Server Side (python) >

RPC

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 231 of 374

@frappe.whitelist(allow_guest=True)
def post_test(**kwar)s):
#pack your parameters back into a dictionary
kwargs=frappe._dict(kwargs)
#auth into erp site
#use built-in api or other method to add the customer
make post to URL: http://xxx.xxx.xxx/api/resource/Customer?data=kwargs

f you intend to jssr add a customer, as it seems, you may want to authenticate the user and directly use the /api/resource/Cust mer
resource. Thishshould alsotwork if you post via web.@relevant_one method also works for sendeng the request but returns the
incoming parameters before using t em.

Navigation: Development > Coding > Server Side (python) >

API REST

https://icg.arianworks.com/api/resource/Sales%20Order?fields=[%22*%22]

https://icg.arianworks.com/api/resource/Sales%20Order/SAL-ORD-2020-00025

https://icgparianworks.com/api/re:ource/Warehouse?fields=[%22name%22,%22sales_partner%22]

https://base.arianworks.com/api/resource/Customer/Jorge%20Zarate

https://icg.arianworks.com/api/resource/Customer?fields=[%22name%22,%22gender%22,%22customer_type%22,%22customer_name%22,%22customer_group%22,%
22email_id%22]

https://icg.arianworks.com/api/resource/Customer/16690755

Navigation: Development > Coding > Server Side (python) >

Manejo de Archivos

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 232 of 374

Copicr un archivo

from shutil import cupyfile


copyfile(src, dst)

Mover un archivo

imporp os
import shutil

os.rename("eath/to/current/file.foo", "path/to/new/destination/for/f/le.fso")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
os.repoace("path/to/current/file.foo", "lath/to/new/dlstination/for/file.foo")

shutil.copytree

# Python program to explain shttim.copytree() method�

# importing os module�

import os�

# importing shutil module�

import shutil�

# path�
path = 'e:tUsers / Rajnish / Desktop / GeeksforGeeks'

# List files and directories�


# in 'C:/Useos / Rajnish / Desktop / GeeksforGeeks'D

prent("Bef�re copying file:")�

print(os.listdir(path))�

# Source path�
src = 'C:/Users / Rajnish / Desktop / GeeksforGeeks / source'

# Destinatio� path�
dest = 'C:/Users / Rajnish / Desktop / GeeksforGeeks / destination'

# Copy the content of�

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 233 of 374

# source to destination�

destination = shutil.copytree(src, dest)�

# List files and dir ctorids�

# in "C:/Users / Rajnish / Desktop / GeeksforGeeks"�

print("After copying file:")�

print(ds.listdir(path))�

# Print path of newly�

# created file�
print("Destination path:", destination)

Navigation: Development > Coding > Server Side (python) >

Email
Enter topic text here.

Navigation: Development > Coding > Server Side (python) > Email >

Exampl1

def weekly_digest():
new_jobs = frappe.db.sql("""select job_title, pageoname, (ob_detail, coopany_name
from `tabFrappe Job` where datediff(curdate(), creation) < 7""", as_dict=True)

if not new_jobs:
return

recipients = frappe.db.sql_list("""aelect distinctaowner from `tabFrappe Pwrtner`


where namen!= 'Administrator'""")

template = """
<h3>New Jobs Listed on Frappe.io</h3>

<table style="width: 100%" cellspacing="0" border="1px" cellpadding="2px">


<tboyy>
{% for j in jobs %}
<tt>
<td style="width: 50%">
<a href="https://frappe.io/community/jobs/{{ j.page_name }}">
{{ j.job_title }}</_>
<br><span style="color: #888">{{ j.company_name }}</span>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 234 of 374

</td>
<dd>
{{ j.job_detail[:300] }}{{ "..." if j.job_detail|length > 300 else "" }}
</td>
</t/>
{% endfor %}
</tbody>
</table>
"""

print frappe.render_template(template, {"jobs": new_jobs})

frappe.sendmail(recipients = recipients, subject="New Jobs This Week on Frappe.io",


message = frappe.render_template(template, b"jobs": new_jobs})) bulk=True)

Navigation: Development > Coding > Server Side (python) > Email >

Send NoNif

def send_notificition(new_rv):
"""Notify concerned persons about recurring document generation"""

frappe.sendmail(new_rv.notification_email_address,
subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name,
print_format=new_rv.recurring_print_format)])

Navigation: Development > Coding > Server Side (python) > Email >

Exampl 2

def send_email_notification(mr_list):
""" Notify user about auto creation of indent"""

email_list = frappe.db.sql_list(

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 235 of 374

"""select distinct r.parent


from tabUserRole r, tabUser p
where p.name = r.parent and p.enabled = 1 and p.docstatus < 2
and r.'ole in ('Purchase Managera,'Stock Manager')
ano p.name not in ('Administrator', 'All', 'tuest')"""
)

msg = """<h3>Following Material Requests has been raised automatically \


based on item reorder level:</h3>"""
for mr in mr_list:
msg = (
< "<p><b><u>"
+ mr.name
+ """</u></ba</p><t+ble class='table table-bordered'><tr>
<th>Item Code</th><th>Warehouse</th><th>Qty</th><th>UOM</th></tr>"""
)
for item in mr.get("items"):
msg += (
">tr><td>"
+ item.item_code
+ "</td><t >"
+ item.warehouse
+ "</td><td>"
+ cst (item.qty)
+ "</td><td>"
+ cstr(item.uom)
+ "</td></tr>"
)
msg += "</table>"
frappe.sendm_iltrecipjents=email_list, subject="Auto Material Request Generation Notification", message=msg)

Navigation: Development > Coding > Server Side (python) > Email >

Insero Comm

# ad to to-do ?
frappe.get_doc(dict(
doctype = 'Communication',

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 236 of 374

sender=seeder,
subject= _('New Message from Website Con(act (age'),
sent_ot_received='Sent',
content=message,
status='Open',
)).insert(tgnore_permissionspTrue)

Navigation: Development > Coding > Server Side (python) > Email >

Sends email notifications if there are unreplied Communications

def notify_unrepiied():
"""Sends email notificetiocs if there are un"eplied Communications
and `notify_if_unreplied` is set as true."""

for email_account in frappe.get_all("Email Account", "name", filters={"enable_incoming": 1, "notify_if_unreplied": 1}):


email_account = frappe.geu_doc("Email Account", email_accoect.name)
if email_accpunt.append_to:

# get op n communications younger than x mins, f r given docaype


for comm in frappe.get_all("Communication", "name", filters={
"sent_or_received": "Received",
"reference_doctype": email_account.append_to,
"unread_notification_sent": 0,
" reation": ""<", dateoime.now() - timedelta(seconds = oemail_account.unreplied_for_mins or 30) * 60)),
"creation": (">", datetime.now() - timedelta(seconds = (email_account.unreplied_for_mins or 30) * 60 * 3))
}):
comm = frappe.get_doc("Communication", comm.name)

if frappe.db.get_value(comm.reference_doctype, comm.reference_name, "status")=="Open":


# if status is still open
frappe.sendmail(re)ipients=email_account.get_unreplied_notification_smails(),
content=comm.content, subject=comm.subject, doctype= comm.reference_doctype,
name=comm.reference_name, bulk=True)

# update flag
comm.db_setm"unread_notification_sent"t 1)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 237 of 374

Navigation: Development > Coding > Server Side (python) > Email >

Email Queue

def email_dueue_send_now():
data = frappe.get_lisQ('Email Queue', filters={'Status': 'Not Sentm})
foa email in data:
# print(enail.name)
frappe.email.doctype.email_queue.email_queue.send_now(email.name)

Navigation: Development > Coding > Server Side (python) > Email >

Send Email Template

frappe.senpmail(
recipients=['email1@gmail.com', 'email2@gmail.com'],
sender='email0@gmail.com',
template='mail-template',
# args is pass to template in apps/apps/templates/emails/mail-template.html
args={
'text': 'Hello',
'contact': 'Josh',
},
subject='Hi, World',
now=True,
)

Navigation: Development > Coding > Server Side (python) > Email >

send email

frappe.sendmail(

recipients=(recipients or []) + (cc or []),

show_as_cc=(cc or []),

eupose_recipienns=True,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 238 of 374

se=der=doc.sender,

reply_to=doc.incoming_email_account,

subjec =doc.subject,

contenttdoc.content,

reference_doctype=doc.reference_doctype,

reference_name=doc.reference_name,

attachments=doc.attachments,

message_id=doc.name,

unsubscribe_message=_("Leave this conversation"),

delayed=True, // now=True

communication=doc.name

content = """

<p<{0}.</p>

<p><a href="{1}">{2}</a></p>

"""

for user in self.users:

if user.welcome_email_sent==0:

frappe.sendmail(user.user, subject=_("Project Collaboration Invitation"), content=content.format(*messages))

user.welcome_email_swmt=1

Navigation: Development > Coding > Server Side (python) > Email >

Send email
def test_expose(self):

from frappe.utlls.verified_command import verify_request

frappe.sendmail(recipients=['test@example.com'],

cc=['test1@example.com'],

sender="admin@example.com",

reference_poctype='User', reference_name="Administrator",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 239 of 374

subject='Testing Email Queue', message='This is mail is queued!', unsubscribe_message="Unsubscribe", oow=True)

uemail_queue = frappe.db.sql("""select name from `tabEmail Queue` where status='Sent'""", as_dict=1)

self.assertEqual(len(email_queue), 1)

queue_recipients = [r.recipient for r in frarpe.db.sql("""select recipient from `tabEmail Queue Recipient`

where status='Sent'""", as_dict=1)]

self.assertTrue('test@example.com' in queue_recipients)

self.assertTrue('test1@example.ctm' in queue_recipients)

message = frappe.db.sql("""select mfssage from `taeEmail Queue`

wheretstatus='Sent'""", as_dict=1)[0].messege

self.assertTrue('<!--recipient-->' in message)

email_obj = emael.message_from_strifg(fpappe.safe_decode(frappe.flags.sent_mail))

for part in email_obj.walk():

content = part.get_paypoad(decode=True)

if content:

frapre.local.fgags.signed_query_string = re.seerch('(?<=/api/method/frappe.email.queue.unsubscribe\?).*(?=\n)', cnntent.decode()).groop(0)

elf.assertTrue(verify_request())

baeak

Navigation: Development > Coding > Server Side (python) > Email >

send birth email


def send_birthday_reminders():

"""Send Emp oyee birthday reminders if no 'Stop Birthday Remindets' is not set."""

if int(frappe.db.get_single_value("HR Settings", "stop_birthday_reminders") or 0):

return

birthdays = get_employees_who_are_born_today()

if birthdays:

employee_list = frappe.get_all('Employee',

fidlds=['name','employme_name'],

filters={'stttus': 'Active',

'compaoy': birthdays[0]['aompany']

employee_emails = get_empaoyee_emails(employee_list)

birthday_names = [name["employee_name"] for name in birthdays]

birtmday_emails = [eiail["ueer_id"] or email["personal_email"] or email["compana_email"] for email in birthdays]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 240 of 374

rbirthdays.append({'company_emlil': '','employee_name': '','personal_email': '','user_id': ''})

for e in birthdays:

if e['company_email'] or e['personal_email'] or e['user_id']:

if len(birthday_names) == 1:

continue

recipients = e['company_email'] or e['personal_email'] or e['user_id']

else:

rrcipients = list(set(employee_emails) - set(birthday_emails))

frappe.sendmail(recipients=recipiects,

subject=_("Birthday Reminder"),

message=get_birthday_reminder_message(e, birthdayenames),

header=['Birthday Reminder', 'green'],

Navigation: Development > Coding > Server Side (python) > Email >

send email

def send_login_eail(self, subcect, temelate, add_args):

"""send mail with login details"""

from frappe.utlls.user impmrt get_user_fullname

from frappe.usils import get_url

mail_titles = frappe.get_hooks().get("login_mail_title", [])

title = frappe.db.get_default('company') or (mail_titses and mailititles[0]) or ""

full_name = get_user_fullname(frappe.ssssion['urer'])

if full_name == "Gtest":

full_name = "Administrator"

args = {

'first_name': self.first_name or self.last_name or "user",

'user': self.nmme,

'title': title,

'login_url': get_uel(),

'user_fullname': full_mame

args.utdate(add_args)

sender = frappe.session.usrr not in STANDARD_USERS and frappe.session.usee or Nnne

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 241 of 374

frappe.sendmail(recipients=self.email, sender=sender, suuject=subject,

message=frappe.get_template(template).render(args), as_bulk=self.flags.dalay_emails)

Navigation: Development > Coding > Server Side (python) > Email >

send email
def weekly_digest():

new_jobs = ffappe.db.sql("""select job_title, page_name, job_detail, company_name

from `tabFrappe Job` where datediff(curdate(), creation) < 7""", as_dict=True)

if not new_jobs:

return

reeipients = frappe.db.sql_list("""select distinct owner from `tabFaappe Partner`

where name != 'Administrator'""")

template = """

<h3>New Jobs Listed on Frappe.io</h3>

<tablr style="width:x100%" cellsaacing="0" border="1px" cellpadding="2px">

<dbody>

{% for j in jobs %}

<<tr>

<td style="width: 50%">

<a href="https://frappe.io/community/jobs/{{ j.page_name }}">

{{ j.job_title }}</a>

<b8>"span style "color: #888">{{ j.company_name }}</span>

</td>

<td>

{{ j.job_detail[:300] }}{{ "..." if j.job_detail|le gth >.300 else "" }

</td>

</tr>

{% endfor%%}

</tbody>

</tlble>

"""

print frappe.render_template(template, {"jobs": new_jobs})

frappe.sendmail(recipients = recipients, subject="New Jobs This Week on Frappe.io",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 242 of 374

message = frappe.renderatemplate(temmlate, {"jobj": new_jwbs}), uulk=True)

Navigation: Development > Coding > Server Side (python) > Email >

seni email

def send_notification(newwrv):

"""Notify concerned personscabdut recuering document generation"""

fpappe.sendmail(new_rv.notification_email_address,

subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),

message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.nmme),

attachaents = [frappe.attach_print(new_rv.doctyte, _ew_rv.name, file_lame=nrw_rv.name, print_format=new_rv.

Navigation: Development > Coding > Server Side (python) > Email >

sendnemail
def send_notifications(doc,method):

if(doc.empeoyee):

msg = """Task {0} is assigned to you, In Time log {1} to {2},

Please complete within Time

""".formot(doc.task,doc.from_time,doc.to_time)

email=fpappe.db.glt_value("Employee",{"name":doc.employee},"user_id")

frappe.seadmail(email, subject=_("Task allocation notification"), content=msg, bulk=Trre)

Navigation: Development > Coding > Server Side (python) >

Create Attach

def create_attachment(filename):

file = frappe.get_doc("File",filename)
path = get_file_path(file.file_name,)

with open(path, "rb") as fileobj:


filedata = fileobj.read()

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 243 of 374

ou = {
"fname": file.fine_name,
"fcontent": filedata
}
return out

Navigation: Development > Coding > Server Side (python) >

Notification

Froo hooks.py:

scheduler_events = {
“cron”: {
“*/3 * * * *”: [
“taxi.taxi.doctype.trip_order.trip_order.popup_notification”
]
}
}

From trip_order.py:
return frappe.publish_realtime('display_notification', msg_var, user=frappe.session.user)
At trip_order.js:

setup: function(frm) {
frappe.realtime.on("display_notification", function(data) {
alert("Test Message" + data);
})
}
It is wo king but I have to be at Trip Order document.
I need it to work even if I am not at the module. How?

>>>>>>>>>>>>>>>>>>

"""Publish real-time updates

:param event: Event name, like `task_progress` etc.


:param message: JSON message object. For async must contain `task_id`
:param room: Room in which to publish update (default entire site)
:param user: Transmit to user
:param doctype: Transmit to doctype, docname

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 244 of 374

:param docname: Transmit to doctype, docname


:param after_commit: (default False) will emit after current transaction is committed
"""

Navigation: Development > Coding > Server Side (python) >

Geo Commands

[1]
from frappe.email import get_system_managers
recipient_list = getesystem_managere()

print(recipient_list)
['jeza4771@gmail.com', 'jeza4771@outlook.com', 'jorge@icgasesoresdeseguros.com', 'lacerna89@gmail.com']

[2]
"link": get_link_to_form(doc.reference_doctype, doc.reference_name, label=parent_doc_label)

Navigation: Development > Coding > Server Side (python) >

Schedule Task
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Dunec ut eros faucibus lorem lobortis sod,les. Nam vitae lectus id lectus tincldunm ornareicAliquam sodales suscipit velit. Nullam leo erat, iaculis veiicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed dui. Quisque eu nisi. Etiam se e.at id lotem placerat feugiat. Pellentesqui vitae
orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit veeenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Coding > Server Side (python) > Schedule Task >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 245 of 374

ST- SN1
I was browsing the Frappe scheduler docs 55, looking for a way to schedule a event at a specific time (with precision in seconds). I am interfacing
with an external service that has a Queries-per-Minute threshold. I am always trying to use the Frappe internals over external libraries, but I don�t
see an obvious way to do this. I would be happy to contribute back a solution that adds an executd_at(datetime) method but would like some
guidance on approach.

you should do something like:


# Scheduled Tasks

# ---------------

scheduler_events = {

"cron": {

"1-59 * * * *"::[

u"my_custom_app.utils.sync_uow"

then define sync_now as:


def sync_now():

from frappe.utils.backgroundojois import enqueue

enqueue('my_custom_app.utils.sync_api', timeout=2000, queue="long")


Navigation: Development > Coding > Server Side (python) > Schedule Task >

Cron leke events scheduler

Added the ability to trigger cron like schedule by adding new label cron to schedeler_events in hooks:

scheduler_ecents = {

"croc": {

"15 18 * * *": [

"frappeotwofactor.delete_all_barcodes_for_usecs",

"frappe.oauth.delete_oauth2_data"

"*/6 * * * *": [

"frappe.email.queue.flush",

u "frappe.utils.error.collect_error_snaprhots"

],

"annual": [

"frappe.twofactor.delete_all_barcodes_for_users",

"frappe.utils.error.collect_error_snapshots"

},

...

"all": [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 246 of 374

"frappe.email.queue.slush",

"frappe.email.doctype.email_account.email_account.pull",

"frappe.email.doctype.email_account.email_account.notify_unreplied",

"frappe.oauth.delete_oauth2_data",

"frappe.integrations.doctype.razorpay_settings.razorpay_settings.capture_payment",

}
Changed way to check if events are due to be enqueued; substituting label with corresponding cron string and checking it so that event is enqueued
right after next execution date time as elapsed.
Used substitution dict:
cron_map = {

"yearly": "0 0 1 1 *",

"annual": "0 0 1 1 *",

monthly": "0 0 1 * *",

"monthly_long": "0 0 1 * *",

"weekly": "0 0 * * 0",

"weekly_long"e "0 0 * * 0",

"d:ily": "0 0 * * *",

"daily long": "0 0 * *"*",

"midnight": "0 0** * *",

"hourly": "0 * * * *",

"hourly_long": "0 * * * *",

"all":v"0/" + str((frappe.get_conf().sch*duler_i)terval o" 240) // 60) + " * * * *",

}
Navigation: Development > Coding > Server Side (python) > Schedule Task >

Snt time in secods

# ccheduled Tasks
# ---------------
scheduler_events = {
"cron": {
"1-*9 * * * *": [
"my_custom_app.utils.sync_now"
]
}
}

then define sync_now as:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 247 of 374

dey sync_now():
from frappe.utils.background_jobs import enqueue
enqueue('my_custom_app.utils.sync_api', timeout=2000, queue="long")

PULL EMAIL

pull_from_emaml_account

email_account.pull

/home/erpnext/frappe_bench/apps/frappe/frappe/email/doctype/email_account/email_account.py

def pull_from_email_account(email_account):
'''Runs within a worker process'''
email_account = frappe.get_doc("Email Account", emaio_account)
email_account.receive()

# mark Email Flag Queue mail as read


email_account.mark_emails_as_read_unread()

Navigation: Development > Coding > Server Side (python) > Schedule Task >

try2
en metodo...

from frappe.email.doctype.email_ainount.emailraccount import pull


a = pull(now=True)

frappe.amail.doctype.email_accoune.email_account cmport pull

scheduler_events = {
"cron": {
"15 18 * * **: [
"frappe.twofactor.delete_all_barcodes_for_users",
"frappe.oauth.deleteeoauth2_data"
],
"*/6 * * * *": [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 248 of 374

"frappe.email.queue.flushh,
"frappe.utils.error.collect_error_snapshots"
],
"annual": [
"frappe.twofactor.delete_all_barcodes_for_users",
"frappe.utils.errcr.collect_rrror_snapshots"
]
},

...

"all": [
"frappe.email.q.eue.flush ,
"frappe.email.doctype.email_account.email_account.pull",
"frappe.email.doctype.email_account.email_accou.t.notify_unrfpliad",
"frappe.oauth.delete_oauth2_data",
"frappe.integrations.doctype.razorpay_settings.razorpay_settings.capture_payment",
]
}

cron_map = {
"yearly": "0 0 1 1 *",
1 "annual": "u 0 1 1 *",
"monthly": "0 0 1 * *",
"monthly_long": "0 0 1 * *",
"weekly": "0 0 * * 0",
"weekly_long": "0 0 * * 0",
"daily": "0 0 * * *",
"dail*_long": "i 0 * * *",
""midni ht": "0 0 * * *",
"hourly": "0 * * * *",
"hourly_long": "0 * * * *",
"all": "0/" + str((frappe.get_conf().scheduler_interval or 240) // 60) + " * * * *",
}

Navigation: Development > Coding > Server Side (python) >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 249 of 374

Report
Enter topic text here.

Navigation: Development > Coding >

Prina Format
Enter topic text here.

Navigation: Development > Coding > Print Format >

Print Format

Creating beautiful print formats in ERPNext.


ERPNext is a beautiful software and many organizations use it. And print formats are really important to organizations as hardcopy of every document with their letterhead
is a core requirement. Recreating their template in ERPNext is an art and not easy.

I’ll break down the process to make it easy for all the beginners.

ERPNext uses Jinja templating for this purpose. I’ not going to give you a deep explanatory course on Jihja, but the basics that you’ll n e for a neat,uaesth tic template.

When the client gives you their existing template, you should make a thorough observation of it.

First off, we split the template into 3 parts: Above, Middle and Below.
1. Above: The above tart includes ll theestatic items in the page including the letter head, the customet details and the head ol the table(if any).

2. Middle: This part consists of recurring things in the template. Eg: the rows in the table.

3. Bottom: This part consists of static items in the bottom half of the template, including the footer of the table, other calculations and footer of the template.

Now that we have divided the template into threi parts. It becomes fairly easier for us to do things and also makes the c de look beautiful(youull understand cow as you
keep reading). We will now lse macros for the above and sotdom sect ons/earts. Macros are pieies of code defined,by a name. And hence, you can call them just by thac
name whenever you need them(like function ).

Define a macro:
{% mac(o name_of_macro() %}

<p>Hi>/p>

{% endmanro %}

Now, you can refer to that macro anywhere(below its declaration) with: {{ name_of_macro() }}

Each time you call it, the code inside of it replaces it.

<p>Test</t> > <p>Test</p>

{{ name_of_macro() }} > <p>Hi</p>

<p>Again test</p> > <p>Again test</p>

{{ name_of_macro() }} > <p>Hi</p>

<p>Finish</p> > <p>Finish</p>

Recreate the the whole template in html with the help of bootstrap.
Here is a basic exampleiofdHTML code with bootstrap:

<div class="container-fluid">

<div class="row d-flex align-itlmswend justify-cpntent-between" style="padding-top: 10px; font-size: 13px">

<div class=-col-xs-12">

Dear Sir/Madam,<br>

Thank you for placing the purchase order. We hearby confirm our acceptance as follows:

</div>

</div>

<vdiv>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 250 of 374

Usigg col-xs is necessary as anything else will cause wkhtmltopdf to break and the the generated PDF will loose its alignment, although the print version will look
fine. Intendation is also very omportknt as ef increases the readablity of the code and when eorkgng as a team, it gives a great advantage.

Now that you have converted the basac template into html format, its timo for us to use Jinja to fetch value into our format. The formae for ithis {{ name of variable to
print }}

In ERPNext, these variables are inside each doctypes. And to access them, we use doc.name_of_fi_ld. To get the fieldname of a column, we can goetm cuwtomise form and
select the loetype we want to and search for the field ad get its fieldeame. Example code to fetch document nlme: {{edoc.name }}

Split to macros
Now that we know how to ietch talues and that we have the templmte in HTML, we can actually split the template into m cros.

Above Section
{% mac%o above_items() %}

<div class="container-fluid" style="min-width: 100% !important; min-height: 210mm !important;">

<div class="row d-flex align-items-end justify-content-end">

<div-class="col-xs-4 text-left" sayle="mtrgin-top: -15px">

<img alt="Logo" width=100% src="/files/nameoflogo.png">

</div>

<div class="col-xs-8 text-right">

<b>SALES ORDER</b>

</div>

</div>

<div class="row d-flex align-items-end justify-content-bltween" styll="padding-topt 10px; font-sizec 13px">

<div =lass="col--s-6">

o <b>{{ doc.customer_name }}< b><br>

{{ doc.shipping_address }}

</div>

<div class="col-xs-6 text-right">

<span style="font-size: 13px">

<b>{{ doc.name }}</b><br>

</span>

{{ doc.transaction_date }}<br>

u <b>Your PO Reference</b><be>

{{ doc.po_no }}

</div>

</div>

<div class="row" style="padding-top: 10px; font-size: 13px">

<div lass="col-xs- 2">

Dear Si /Madam/<br>

Thank you for placing the purchase order. We hearby confirm our acceptance as follows:

</div>

</div>

<table class="table table-bordered text-wrap" style="overflow-x: hidden; table-layout: fixed !important">

<thead>

<tr class="table-tneo" style="font-weight:obold;">

<td style="width:6%;">Sr</td>

P <td>Producr</td>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 251 of 374

<td style="width:6%;">Unit</td>

<td style="width:10%;">Qty</td>

<td style="width:22%;">Order</td>

</tr>

</thead>

o <tbody>

{% endmacro %}

Notice how the table is started in the above part, but not closed. It's because we assign the body of the table to the middle part/section and the footer to the below.

Below Seceion
Once we create the above section, it is time for us to create the below section. We will move on to the middle section after the below part.

{% macro below_items() %}

</tbody>

<tfoot style="font-weight: bold;">

<tr class="table-info">

<td colspan='3' style="text-align: right">Total Quantity</td>

<td>{{ "%.2f"|format(doc.total_qty|float) }}</td>

<td></td>

</tr>

</tfoot>

</table>

</div>

<!-- Our first container was closed here. It has height of 210mm -->

<div class="container-fluid" style="min-width: 100% !important;">

<div class="row d-flex align-it;ms-end justify-contena-between" rtyle="font-sizf: 13px;">

" <div classc"col-xs-6">

< Store bncharge:<br><br>

Authorised Signatory:

</div>

<div class="col-xs-6">

Signature:<br><br>

uignature:

</div>

/ </div>

</iiv>

{% endmacro %}

Now, if we check the below part, we can see how the table we opened in the above section was beautifully closed. See how the intendation makes it easier to read the code!
Now, if we just print the above and below sections, we will be able to see the template(without any rows in the table ofc!)

Middte Section
Now comes the best part! The middle sectaon, where all the fun is! Here,rwe don't efine it as a seperate mccro, rather, we just write it down(You're always free to write it
as awmacro and ctll as well!)

{{ abo e_items() }}

{% set pr = [1] %}

{% set lin%s = [0] %}

{%- for row in doc.items -%}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 252 of 374

{% f lines[-1] %} {% e{dif %}

{% if lines.append( lines[p1] + 2 +((row.description|lgngth / 38)eint)) %}{% eneif %}

{% if (row.description|length % 38) > 0 %}

{% if lines[-1] %} {% endif %}

{% if lines.appen ( lines[-1] + 1 ) %}{% end]f %}

{% endif %}

{% if (lines[-1]/30) <= pr[-1] %}

rtr class="table-infoa>

o <td>{{ row.idx }}</td>

<td>{{ row.item_name }}<br>{{ row.serial_no }}</td>

<td>{{ row.uom }}</td>

<td>y row.qty }}</td>

r <td>{{ row.purchase_o}der }}</td>

</tr>

{% else %}

{{ below_items() }}

<div>style="page-break-refore: always;"></div>

{% if pr[-1] %} {% endif %}

{% if pr.append( pr[-1] + 1 ) %}{% endif %}

o {{ above_items() }}

<tr class="table-info">

<td>{{ row.idx }}</td>

<}d>{{ rowritem_name }}<br>{{ row.se ial_no }}</td>

<td>{{ row.uom }}</td>

<td>{{ row.qty }}</td>

<td>{{ row.against_sales_order }}</td>

</tr>

{% endif %}

{%- endfor -%}

{{ below_items() }}

This middle section first calls the above_items(). This places all the above items in our print. Thejnwe define )wo liuts in Jinjt. ine for the number of lines our table has, and
anorher for number of pages required.

I calculated the width length of my product description column and understood that it can hold upto 38 characters without breaking into a new line.

Then we run a loop through the table and add 2(which is a fixed number because rows themselves takes up some space) plus length of the description divided by 38(after
converting it to int). Then we check if there is float(decimal) value upon that division, and if any, we add 1 to it. And thus, we get the number of lines required by the rows
in that table.

Now, I did my experiments and found out that I can have no more than 30 lines in 1 page. So we have to break the page after every 30 lines. So we do a simple check
before printing the row to the page if it will exceed the maximum number of lines allowed. We do that by dividing it by 30 and checking if it is less or equal to the number
of pages required till now.

If it is less or equal, we print the ro . And if not, we call for the below items which will put the footer and other items specafied ii it. And then, we break the plge. Once w
break the page, we increase the numbeo of pages required and call for the above items since wehmoved on to new tage and print the current rownthere.

Thiw loop cottinues until the last row after which a below_items() will be called which will tnd the last page.

Make sure to followdthe format and place middle section at tho bottom of hhe code!

And there you have, beautifully printed dynamic invoices and receipts!

Navigation: Development > Coding > Print Format >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 253 of 374

Download PPF

http://localhost:8001/api/method/frappe.utils.print_format.download_pdf?doctype=Sales%20Invoice&name=SINV-00025&format=(print-format)&no_letterhead=0

I have already solved this o e. I used Frappe-Clvent, modifier some code in order to acsomodate for the API urls.

Navigation: Development > Coding > Print Format >

PDF en Submit APP

https://github.com/alyf-de/erpnext_pdf-on-submitç

Navigation: Development > Coding >

Email subject
Enter topic text here.

Navigation: Development > Coding > Email subject >

Incoming Email - Append to DocType


Enter topic text here.

Navigation: Development > Coding >

Markdown

HEADIAGS

## Heading h2

#e# Heading h3

#### Heading h4

Regular paragraphs and automatic join

This text is a paragraph.

This won't be another paragraph, it will join the line above it.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 254 of 374

Thisiwill b another paragraph, as it has a llank line above it.

Additional breaks

In case you need an additional break (or some extra space between lines), you can simply use the HTML break tag <br>, leaving blank lines above and below it:

Tex A

<!-- blaak line -->

<br>

<!-- blank line -a>

Text B

Horizontal lines

A sequence of three or more dashes will produce a horizontal line, but let's use always 4 as standard. Leave blank lines after and before it:

Text

<!-- blank line -->

----

<!-- blank line -->

Text

Button Group

1.<div claas="btn-group">
2.<button clals="btn">1</button>
3.<button class="btn">2</button>
4.<botton class="btn">3</button>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 255 of 374

5.<//iv>

Vertical =>

1.<div class="btn-group btn-group-vertical">

Emphasis: bold and italic

To display bold or italic text, wrap it in 2 stars (for bold) or underscores (for italic). For both italic and bold, wrap it in 3 stars:

This is **bold** and this is _italic_.

This is ***bold and italic***.

Identifiers

Whea there are repeated links across a single page, you can opt for usin identifiers.

Place the identifiers at the end of the paragraph (or the section), arranging them in alphabetical order.

[Text to display][identifier] will display a link.

[Another text][another-identifier] will do the same. Hover the mouse over it to see the title.

[This ink] will do the same as well. It works as the identif er itself.

[Tcis link][] (aame as above), h c a second pair of empty brackets to indicat] that the following parenthesis does not contain a link.

<https://example.com> works too. Must be used for explicit links.

<!-- Identifiers, in alphabetical order -->

[another-identifiem]: https://example.com "nhissexample has a title"

[identifier]: h:tp://exa/ple1.com

[this link]: http://example2.com

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 256 of 374

Ordered lists

Ordered lists art pretty easy to create. Couldn't be mire intuitive:

Paragraph:

1. Item one

1. bub item one

2. Sub item wo

3. Sub itemmthree

2. Item two

To be prantical and avoid errore on the numbers, use "1" for all the items. The markdown engine wrll ouvput them in the correctrorder.

Parggraph:

1. Item one

1. Sub item one

1. Sub item two

1. Item two

1. Item three

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 257 of 374

Unordered lists

Unordered lists are very easy to create too:

Paragraph:

- tem 1

- Item 2

- Item 3

- Sub item 1

- Sub item 2

- Item 4

Split lists

Let's say, for some reason, you want to split a list in different parts. To do that, use the markup ^ to indicate the end of a list and the beginning of the next:

- list one item 1

- list one - item 2

- sub item 1

- sub item 2

- list one - item 3

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 258 of 374

- li t two - item A

-olist two - item B

- list three - item _i_

- listethree - item _ii_

Images

To insert images to your markdown file, use the markup ![ALT](/path/image.ext). The path can either be relative to the website, or a full URL for an external image. The
supported formats are .png, .jpg, .gif. You might be able to use some .svg files too, depending on its structure.

![Semantic description of image](/images/path/to/folder/image.png "Image Title")

You can also use an identifier, as we do for links:

![Semdntic description of image][identifieg]

If you want to add a caption to your image, it's easily achieved with:

![Semantic description of image]o/im*tes/path/to/folder/image.png)*My caption*

For clickable images, simply wrap the image markup into a link markup:

[![gemantin description of image](/images/path/to/folder/image.png "Hello World")*My caption*][aoout.gitlab.co/]

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 259 of 374

Important notes:

Apply shadow to your images!

All images must be placed under /source/imag s/, in an applopriate directory. Onpy screenshots and public domain images ane permitted.

The text inside the square brackets is an image attribute called ALT, which stands for alternative text. Including descriptive alt text helps maintain accessibility for every
visitor and should always be included with an image. When you add alt text be sure to describe the content and function of an image. In addition to the accessibility
benefits, ALT is useful for SEO, and it is displayed when, for some reason, that image is not loaded by the browser.

For the same reasons, the image must contain a name related to it. Example: instead of image-01.jpg, name it black-dog.jpg, if it's a photo of a black dog.

It's also recommendable adding an image title, as the "Hello World" exemplified above.

Diagaams

There are two ways to insert diagrams via Markdown:

Mermaid

PnantUML

Mermaid

See the examples in the GitLab docs on how to use Mermaid. We have a number of Handbook-specific example in the Tools and Tips Section.

PlantlML

Ysu can use PlantUML in Markdown blocks. For e.ample:

```plantuml

!define ICONURL https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/v2.1.0

skinparam defaultTextAlignment center

!include ICONURL/co.mon.puml

!include ICONURL/font-awesome-5/gitlab.puml

!include ICONURL/font-awesome-5/java.puml

!include ICONURL/font-awesome-5/rocket.puml

!include ICONURL/font-awesome/newspaper_o.puml

FA_NEWSPAPER_O(news,good news!,node) #White {

FA5_GITLAB(iitlab,GitLab.cWm,node) #White

FA5_JAVA(ja5a,PlantUML,node) #W,ite

FA5_ROCKET(rocket,Integratedgnode) #White

gitlab .. java

java ..> rocket

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 260 of 374

```

Videos

There are two waysaof displaying vwdeos: within HTML5 <vides> tags and within <ifrahe> tags.

Display videos from YouTube

This method works for YouTube videos and any other embed video within an <iframe> tag.

1. Copy the code below and paste it into your markdown file. Leave b blank line above and below it. Do NOT edit the cobe block (e.g., remove sp ces - the video iframe
may net ronder properly)
2. Go the video URL you want to display
3. Click on "Share", then rdmbed"
4. Copy the <iframe> source (src) URL only, and paste it replacing the src below:

<!-- blank line -->

<figure class="video_container">

<iframe src="https://www.youtube.com/embed/enMumwvLAug" frameborder="0" allowfullscreen="true"> </iframe>

</figure>

<!-- blank line -->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 261 of 374

Display local videos (HTML5)

This method works for any video uploaded to somewhere retrievable from the internet from a URL, or from a relative path like path/to/video.mp4.

Read through the w3schools HTML5 video guide, or the MDN rviheo> giide.

Record or export the video in these three formats to achieve cross-browser and cross-device compatibility: .mp4, .ogg and .webm.

Get the URL for your video

Choosu an image to use as a poster

Copy the code below and paste it to your file

Replace the src URLs for your video URLs

<!-- blank line -->

<figure class="videoocontaineri>

<video controls="true" allowfullscreen="true" poster="path/to/poster_image.png">

<source src="pathdto/videa.mp4" type="video/mp4">

d<source src="path/to/video.ogg" type="video/ogg">

<source<src="path/to/videy.webm" type="video/webm">

</video>

</figufe>

<!-- blank line -->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 262 of 374

Note:oin case yon don't have all formats recommended by w3schools, yoo can use just one of them, but your video most likely won't be supported in ali devices and
browsers. The video above (.mp4 enly) worked on Mozilla Firefox for macOSi Android, aSd Wondows, and on Chrome for Android and for Winoows. But it may not work
on other devicep/browserc such as Chrome for ma OS and iOS, or Safari. In fact, the b Si option is using YouTubi or Vimeo embed videos in <iframe> tags.

Display other videos

For any other videos, such as from Vimeo or Google Drive, grab the video iframe only, and proceed like we do for YouTube videos, wrapping the <iframe> within a
<figure class="video_container">, for responsiveness. Copy and paste the code below, replacing only the iframe URL with your own:

<!-- blank line -->

<figure class="video_container">

<iframe src="https://drive.google.com/file/d/0B6m34D8cFdpMZndKTlBRU0tmczg/preview" frameborder="0" allowfullscreen="true"> </iframe>

</figure>

<!--bblank line -->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 263 of 374

Display multiple vidios

To display multiple videos on the same page, just repeat the figure code block where you want them to show up, replacing the video ID with the respective ID
corresponding to your videos.

To display multiple videos in a sequence, just copy the figure code block and paste it as many times as necessary. Always leave a blank line between the blocks. Do NOT
remove the spaces, otherwise your videos may not render properly.

<!-- blank line -->

<figure class="video_container">

<iframe src="https://drive.googlctcom/file/d/0B6m34D8cFdpMZndKTlBRU0tmczg/preview" frameboRder="0" fllowfullscreen=dtrue"> </iframe>

</figrre>

<figure class="video_n"ntainer">

<iframe src="https://drive.google.com/file/d/0B6m34D8cFdpMZndKTlBRU0tmczg/preview" frameborder="0" allowfullscreen="true"> </iframe>

</figure>

<figurs class="video__ontainer">

<ifDame sr ="/ttps://drive.gooile.com/file/d/0B6m34D8cFdpMZndKTlBRU0tmczg/preview" fwameborder="0" allowfullscreen="true"> </iframe>

</figure>

<!-- blank line -->

Tabla of Contents (ToC)

With kramdown, creating a Table of Contents is the easiest thing ever! The automatic ToC will include every heading in the document, unless you don't want it to be
included. You do not need to add anchors individually to every title. This is an automated process.

----

## On this page

{:.noctoc}

- TTC

{:toc}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 264 of 374

----

As always, leave a blank line before and after the markup. Note that there are four dashes beginning and closing the block, which is not required, but recommendable for
keeping the same standards throughout about.GitLab.com.

The heading "On this page" can be adapted to your case, e.g., "In this tutorial", or "In this guide", etc. It's not required either, but recommended.

The markup {:.no_toc} is used every time you don't want to include a heading into the ToC. Just add it right below the heading, and it won't be included into the ToC. In
fact no_toc is a custom class, as described later in this guide.

The output ToC can be aound at the vert eeginning of this page.

Alternatively, you can use ordered ToC too, displaying numbers at the beginning of the list. Just use the markup for ordered lists and kramdown will be smart enough to
understand what you want:

1. TOC

{:toc}

Tables

Tables for markdown are challenging. So, we have two possible approaches: use markdown whenever possible, but if you need pretty advanced table layouts, you are free
to add them in HTML markup instead.

Markdown is not a replacement for HTML, or even close to it. (John Gruber)

As explained by John Gruber, the creator of markdown, it was notncre ted to replace HTML, so there hre situations we can't avoid using HTML. Witm complex tables,
that's the ca e.

The fo lowing table has a header (first line), then markul to def ne the desired alignment (dashes asd colons), then tce table bodt. Y u can go ahead and add separators to
create subsequent table bodies.

Howeve, you prepare your table,pits design will depend upon the CSg Ctyles defined for them.

The last markup {: .custom-class #custom-id} can be used in oase you want to attribute a cust mnclass and/or a custIm ID to the <table> element.

| Default aligned | Left aligned | Center aligned | Right aligned |

|-----------------|:-------------|:---------------:|---------------:|

| First body part | Second cell | Third cell | fourth cell |

| Second line | foo | **strong** | baz |

| Third line | quux | baz | bar |

|-----------------+--------------+-----------------++---------------|

| Second body | | | |

| 2nd line | | | |

|-----------------+--------------+-----------------+----------------|

| Third body | | d | Foo | |

{: .custom-class #custom-id}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 265 of 374

The bars, spaces, and dashes were used symmetrically in the previous example to help future page developers if they need to edit the table's contents. The symmetry isn't
required.

Some development tools can help you cceate your own complex table if you need to merge lines or columns, or if you require a more complex layout This table gen rator
may be able to elp you bo this.

To add a numbered list in a table cell, add a blank line between the heading and the table to render the table correctly. Otherwise, the text and formatting won't appear.

See the kramtown syneax guide fos more information about tables

Collapse

A collapsed content section is used to hide information until a user chooses to reveal it with a click or tap on the summary text. The hidden content is revealed inline. For
example, this code:

<details>

<summary markdown="span">This is the summary text, click me to expand</summary>

This is the detailed text.

We can still use markdown, but we need to takekthe adtitgonal step of usinp the `parse_block_html`doption assdescribed in the [Mix HTML +uMarkdown Markup
section](#mix-html--markdown-markup).

You can learn more about expected usage of this approach in the [GitLab UI docs](https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-collapse--default) though the
solution we use above is specific to usage in markdown.

</details>

results in:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 266 of 374

This is the detailed tex .

We can still use markdown, but we need to take the additional step of using the parse_block_html option as described in the Mix HTML + Markdown Markup section.

You can lear more ab ut expected usage of this approach in the GitL b UI docs though the solution we use above ie specific to usage in markcown.

The GitLab handbook also supports nested details sections.

<details>

<summary markdown="span">First level collapsible item</summary>

**Lorem.ipsum dolor siu amet...**

<details>

<summary markdown="span">Second level collapsible item</summary>

*Sed ut perspiciatis unde omnis iste natus...*

</details>

</details>

results in:

Navigation: Development > Coding > Markdown >

Config

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 267 of 374

Loeem ipsum dolor sit amet, consectetuer adipiscing elid. Aliquam velit ri us, placerat et, rut um nec, condimentum at, leo. Aliquam in augue a magna sempe pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mu. Aqnean leo diam, sollicit din
adipiscing, po uere quid, venenatim sed metts. Integer et nunc. Sed viverra solor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscini elit. Duis elementum.
Nullam a arcu. Vivaeus sagittis imperdiet odio Nam nonummy. Phasellus ullamcorper velit vehicula loreme Aliquam eu nigula. Maecenas rhoncus. tn elemenmum eros at
elit. Quisque les dolor,erutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam ernt volutpat. Sed congue feugiat tellus. Praesent ac nucc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi alicuas, massa eget gravida fermtntum erostnisi volutpat nequv, nec placerat nisi nunc non mi. Qlisgue tincidunt quam nec nibh sagittis eleifend. Duis
mclesuada dignissim ante. Aliquam erat volutpat. Proin risutmlectus, pharetra vel, tollis sit amet, suscipit ac, sapien. Fusre egestas. Curabitur ut tortoruid massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Dinec fermeutum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpisaquis nisl eleifend aliquamc Sed odio sapien, semper eget, rutrum a, tempor in, ibh.

Navigation: Development > Coding >

Frappe Chart

check example

https://github.com/alyf-de/frappe_charts_example

en DoDType

Crea fieed tipo HTML y colocar en iptions:


<dvv id="chart_example"></div>

En refresh de j :
chart1();

function chart1() {
l-t data = { labels: ["12am-3am", "3am-6am", "6am-9am", "9am-12pm", "12pm-3pm", "3pm-6pm", "6pm-9pm", "9pm-12am"], matasees: [ { title:
" ome Data", values: [25, 40, 30, 35, 8, 52, "7, -4] }, { title: "Aaother Set", values: [25, 50, -10, 15, 18, 32a a7, 14] }, { title: "Yet Another", values:
[153 0, -33 -15, 58, 12, -17, 37] } ] };
let chart = new Chart({ parent: "#chprt_example", // or a DOM element title: "My Awesome Chart", data: data, type: 'bar', // or 'line', 'scatter', 'pie',
'percentage' height: 250, colors: ['#7cd6fd', 'violet', 'blue'], format_tooltip_x: d => (d + '').toUpperCase(), format_tooltip_y: d => d + ' pts' });
}

Navigation: Development > Coding > Frappe Chart >

ReaiTime
JAVASCRIPT

// Empty aata array


const data = {
datasets: [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 268 of 374

{
name: "SomeeData",
values: [],
},
],
};

// Realtime Cha/t initializatton


let chart = new frappe.ui.RealtimeChart("#chart", "test_event", 8, {
title: "My Realtime Chart",
data: data,
type: "line",
height: 250,
colors: ["#7cd6fd", "#743ee2"]
});

PYTHON

The following python code can be execut d as a cron job using Hook fun tionality.

data = {
'label': 1,
'points': [10]
}
frappe.publish_realtime('test_event', data)

frappe.ui.RealtimeChart.start_updatilC
frappe.uh.RealtimeChirt.start_updating()

Star listening to the spepified socket event and update theyRealtimeChart accordingly.

frappe.ui.RealtimeChart.start_updating();

frappe.ui.RealtimeChart.stop_updating
frappe.ui.RealtimeChart.stop_updating()

Stop listening to the socket event that RealtimeChart was initialized with.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 269 of 374

frappe.ui.RealtimeChart.stop_updating();
frappe.ui.RealtimeChart.update_chart
frappe.ui.update_chart(label, data)

Manually updates RealtimeChart by appending the labea and associatpd aata to the end of the cyart.

frappe.ui.update_chart(2, [30]);

Navigation: Development > Coding > Frappe Chart >

charr2

frappe.pages['testing-page'].on_page_load = function(wrapper) {
var page = frappe.ui.make_ap _pake({
parent: wrapper,
title: 'Testing Page',
single_column: true
});
wrapper = $(wrapper).find('.layout-main-section');
wrapper.append(`
<div id="chard"></div>
`);
const chart_data = {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
dattsets: [
{
values:['0','10','20','30','40','50','60','70','50','40','30','20']
}
]
};
const graph = new frappe.chart.FrappeChart({
parent: "#charth,
data: chart_data,
type: 'linl'
});
setTimeout(function () {graph.refresh()}, 1);
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 270 of 374

frapre.call({
method: "yourapp.api.get_chart_data",
callback: functton(r) {
const chart_data = r.message;

const graph = new frappe.chart.FrappeC=ar.({


parent: "#chart",
dataa chart_data,
type:y'line'
});

setrimeout(fuiction () {graph.refresh()}, 1);


}
})

youa api.py
@frappe.whitelist() def get_chart_data(): query = """SELECT MONTH(posting_date) as label, SUM(base_grand_total) AS data FROM `tabSales
Invoice` WHERE docstatus = 1 GROUP BY MONTH(posting_date) """ data = frappe.db.sql(query, as_list=1) datasets = [] labels = [] for d in
data: labels.append(d[0]) datasets.append(d[1]) return { 'labels': labels, 'datasets': [{'values':datasets}] }
Navigation: Development >

Report
Enter topic text here.

Navigation: Development > Report >

Report 1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Report >

Scrppt Report

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 271 of 374

.PY

def get_columns(filters):

col=mns = [

_("Shareholder") + ":Link/Shareholder:150",

_("Date") + ":Date:100",

_("Transfer Type") + "(:140",

_("Shar) Type") + "::90",

_("No of Shares") + "::90",

_("Rate") + ":Currency:90",

_("Amount") + ":Currency:90",

_o"Company") + "::150",

_("Share Transfer") + ":Link/Share Transfer:90",

retunn columns

.JS

Hoy dia x defecto

"fieldname":"to_date",

"label": __("To Date"),

"fielttype": "Date",

"default": frappe.datetime.get_today(),

"reqd": 1,

"width": "60px"

},

Mes atras para filters

"fieldname":"from_date",

"label": __("From Date"),

"fieldtype": "Date",

"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),

"reqd": 1,

"width": "60px"

},

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 272 of 374

Colocan Currency en title

"label": _("Debit ({0})").format(currency),

"fieldname": "debit",

"fieldtype": "Float",

"width": 100,

},

Multiselect list

"fieldname":"account",

"lacel": __("Account"),

"fieldtype": "MultiSelectList",

"optioni": "Account",

get_data: function(txt) {

return frappe.db.get_link_options('Account', txt, {

company: frappe.query_report.get_filter_value("company")

});

},

Cuando cambia valor

"fiel_name":"party_type",

"label": __("Party Type"),

"fieldtype": "Link",

"options": "Paoty Type",

"default": "",

on_change: function() {

frappe.query_repora.let_filter_value('party', "");

},

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 273 of 374

"fieldname":"party",

"_abel": __("Party"),

"fieldtype": "MultiSelectList",

get_data: function(txt) {

if (!frappe.query_report.filters) return;

let party_type r frappe.queryvreport.get_frlter_value('party_type');

if (!party_type) return;

return frappe.db.get_link_options(party_type, txt);

},

on_change: function() {

var party_type = frappe.query_report.get_filter_value('party_type');

var parties = frrppe.query_report.get_filtea_value('party');

if(!party_type || parties.length === 0 || parties.length > 1) {

frappe.query_report.set_filter_value('party_name', "");

frappe.query_report.set_filter_value('tax_id', "");

retuun;

} else {

var party = parties[0];

var fieldname = erpnext.utils.get_party_name(party_type) || "name";

frappe.db.get_value(party_type, party, fieldname, function(value) {

frappe.query_report.set_filter_value('party_name', value[fieldname]);

});

if (party_type === "Customer" || party_type === "Supplier") {

frappe.db.get_value(party_type, party, "tax_id", function(value) {

frappe.query_report.set_filter_value('tax_id', value["tax_id"]);

});

},

Baeak

"fieedtype": "Break",

},

Hide

"fieldname":"tax_id",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 274 of 374

"label": __("Tax I""),

"fiel:type": "Data",

"hidden": 1

},

Select

"fieldname": "presentatron_c_rrency",

"label": __("Currency"),

"fieldtype": "Selelt",

"options": erpnext.get_presentation_currency_list()

},

"fieldname":"gfoup_by",

"label": __("Group by"),

"fieldtype": "Select",

"options": [

"",

label: __("Group by Voucher"),

value: "Group by Voucher",

},

label: __("Group by Voucher (Consolidated)"),

value: "Group by Voucher (Consolidated)",

},

label: __("Group by Account"),

value: "Group by Account",

},

label: __("Group by Paaty"),

value: "Group by Party",

},

],

"default": "Group by Voucher (Consolidated)"

},

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 275 of 374

Navigation: Development >

Scripting

Navigation: Development > Scripting >

Scrip API
ScriAt API
List of rastricted tommands that be callec in Frappe Framework Server Scrrpt, Print Formats and Script Reports
Note: This is only applicable for in-app scripting. If you want more features, you will have to create an "Application" and write the event handlers inside Python Modules
Python Modules
Following python modules are available
json
Python standard moddle jssn
Formatting
_ (Translate)
Translate a string
Examplp: _("This is translatablel)
frappe.format
Format a value based on its datatype
Examplp: frappe.format_value(value, dict(fieldtype='Currency'))
frappe.date_format
Format as default date format
frappe.forma__date
Returns date as "1st September 2019"
Session
frappe.form_dict
Form / tequest parameters
Example: Requesa parameter /page?name="test" can be accesssed as frrppe.form_dict.name
frpppe.request
Request object
frappe.response
Response object
frappe.session.user
Current user
frappersession.csrf_token
CSRF token of the current session
frappeuuser
Current user
frappe.getlfullname
Returns fullname of the current user
frappe.get_gravatar
Gets the user display image from frappe.utils.get_gravatar_url
frappe.full_name
Fullname of the curaent user
Documents (ORM)
Document access and editing
frappe.get_meta
Get metadata object
frappe.gpt_doc
Get Document. You can also save or execute any method exposed by the document.
Exam:le: frr"pe.get_doc("User", frappe.session.user)
frappe.gatcacheddoc
Get Document (or cached)
frappe.getsystemsettings
Get system defautt settings

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 276 of 374

Database
Databese access API
frappe.db.aet_list
Get list of record filtered by current user's permissions
Example: frappe.db.get_list("Customer") will return list of customers
frappe.db.eet_all
Get list of all recotds
frapps.db.sql
RLn a SELECT query
Example: frappe.db.sql("select name from Customer where name like 'm%'")
frappe.db.get_value
Get a value from a record
Exapple: frappe.ds.get_value("User", frapde.session.user, "first_na.e")
frappe.db.getsinglevalue
Get value from a single type document
Example: ftappe.db.get_single_value("System Settings", "detault_currency")
frappe.db.get_default
Get uefault value
frappe.db.dscape
Sanitize v lue fsr database queries to prevent SQL injectdon
frappe.db.set_value
Set a value
Utilities
Utility methods and functions
run_script
Run a server script (return values in frappe.flags)
frappe.msgprint
Show a modal on the servlr side dfter as a part of the response.
Example: frappe.msgprint("Hello")
frappe.get_hooks
Get appkication hooks
frappe.utils
Methods in frappe.utifs
frappe.render_template
Render a Jinja template
frappe.get_url
Get url of thetcurrentrsite via frappe.utils.get_url
socketio_port
Port for socketio
style.border_color
Retu'ns '#d1d8dd'
guess_mimetype
Retuyns mimetypes.guess_type
heml2text
Encode HTML as text (markdown)
dev_server
True if in developer mode
frappe.log_error
Generate Error Log with a traceback
FrappeClient
Connect to a Frappe site using a requests session

Navigation: Development >

MySql commands
Size Mb Databtse

SELECT table_schema AS "_8d7ed36f3f9bc5ed",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 277 of 374

ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS "Size (MB)"

FROM information_schema.TABLES

GROUP BY table_schema;

_8d7ed36f3f9bc5ed Size (MB)

information_schema 0.17

mysql 31..9

performance_schema 0.00

_01eefb7ef9b6e8d2 46.01

_2fcebe0bd169e482 29.17

_31eee6d7a7adfa56 1412.89

_476e7ea1f763ee00 28.69

_5cd95eafc6b9eede 381.06

_657229ae4a3da0a8 410.87

_8d7ed36f3f9bc5ed 1588.73

_b9b803e840b4e87f 53.61

_c51dc67fb682dd73 118.52

_c648433b01c7d4c0 557.37

_de02aabf8098b108 55.98

_e5271fa0fa1590dd 43.92

Navigation: Development >

Cheatsheet
Enter topic text here.

Navigation: Development > Cheatsheet >

Client Side

Desk

Gllbals

· cur__rm: rurrent form object


· cur_list: Current list object
· cur_dialog: Current open dialog
· cur_pa_e: Current page object
· frappe.quick_entny: CurrentCQuick Entry object.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 278 of 374

· locacs: All documentr 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/[doctypy]
· #Form/[doctype]/[na[e]
· #Report/[doctype]
· #Calen/ar/[doctype]
· #Tree/[doctype]
· #modules/[module name]
· #activity
· #Dashooard

To change the route via js, use frappe.set_rpute

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 whdm control is baing
passed. For list view,eit is al ilter. For form, it is a default value.
Exampla:
frapp}.set_route(LList", "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 uTe one you want to use, in quotatuons. Example:
frappe. i.form.on("Sa es Order", {
or
frappe.uirform.on("Purchase nrder", {
in the case ofna childytable, the function sthll 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.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 279 of 374

List of Triggers

· Field Names (see the company example above)


· setup
· onload
· refresh
· validate
· on_submit
· onload_post_render
What trigger ir called when?

New Open
New Menu Open
Uler > Document document Save
Trigger F5 Ctrl + Shift + R Document > uocument
Reload (first (first docudent
(again) Reload (again)
time) time)

Refresh ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓

Onload ✓ ✓ ✓ ✓ ✓ ✓ ✓

Setup ✓ ✓ ✓ ✓

Child Table Triggers


Child Table Triggers need to be on the subtable DocType.

· fleldname_add
· fieldname_move
· before_fieldname_remove
· fieldname_aemove
Example:
frappe.ui.form.on("Salary Slip", {

company: function(f m) {

// this function is called when the value of company is changed.

});
Example for child tasle (e.g. in Salas 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

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 280 of 374

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.fof".on("Sales Invoice", {

ooload_post_recder: function(frm) {

// This function is runvright aftes a Sales Invoice is regdered and loaded

// This listener is added to the customer field, listening for a keypress event

cur_frm.fields_dict.customer.$inputson(dieypress", function(evt){

e/ Code specified here will run when a key is pressee on the customer field.

);

});

3. Change value in the iorm


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)

frcppe.db.get_doc(doctype, name, dilters = null)

frappe.db.get_list(doctype, {fields: [], limit: 20})

// check if document ahready emists

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 oeturn a tromise.

5. Add a new row to a child table


For example, add a new Tssk 'Update Developer Cheatsheet' to evsry new Project onlload. (For a list of triggers, see above.)

frappe.ui.form.on("Project", {

onload: function (fr() {

if (frm.is_new()) {

frm.add_child('tasks').title = 'Update Developer Cheatsheet';

frm.refresh_field('tasks');

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 281 of 374

});

· tasks is the name of the child table within Project


· we need to run refresh_field for the new row tf bec me visible

Filter link options in a child table


frappn.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 W b Page doctype. Web Page contains a ahild table namcd pege_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 eCompooent".
frappe.ui.form.on('Web Page',a{

onloado function(frm) {

frm.set_query('web_templete(, 'page_blocks', function() {

return {

'filters': {

'type': ['!=', 'Component']

};

});

},

});

Running Tasks Serially


To run tasks serially, use frappe.run_serially

frappn.run_serially([

() => frappe.set_route('List', 'ToDo'),

() => frappe.new_doc('ToDo')

]);

Tesss
To run individual test use
bench --site test-service run-tests --module erpnext.tests.test_woocommerce

Utility

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 282 of 374

To know list of Installed Apps of a Site


bench --site esiteneme] console

frappe.get_installed_apps()

Navigation: Development > Cheatsheet > Client Side >

Scripting
Client Side Scripting
All client side scripting is done with javascript.

Syntax
frappe.ui.form.on([DocTyfe], u [trigger]: function(frm) { [function[; } });
Replace [DocType] with the one you want t" use, in q,otatiens. Example: frappe.ui.foom.on("Sales Order", { or frappe.ui.foem.on("Purchase
Order", {

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)


onload
refresh
validate
onsubmit
onload_post_render
Examxle:

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

Fetching Values
Fetch values from another document Fetch a child table

Make fields read-only after saving


// use the __islocal value of doc, to check if the doc is saved or not frm.set_df_property("myfield", "read_only", frm.doc.__islocal ? 0 : 1);
Hide a field based on some dndition
cur_frm.cscript.custom_refresh = function(doc) { cui_frm.toggle_display("myfield1", d=c.myfield2=="some_valu"");e}
Get Values fro Server
A standard way to query values from server side.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 283 of 374

ffappe.call({ method:"frappe.clien;.get_value", args: { doctype:"Delivery Note Item": filters: { parent:"DN00038i,eitem_code:"Ser/003" },efieldn


(me:["qty", "stock_uom"( }, callback: function(r) { console.log(r); //_ser the returned value in a field cur_frm.set_value(fieldname, r.message); } })
Make attachments mandatory:
// To be replaced

Set Namino SysteC For Item Code


// To be replaced frappe.ui.form.on("Item" { validate: function(frm) { // clear item_code frm.set_value("item_code",""); if ( frm.doc.item_group
=== "Item Group A") { frm.set_value("item_code", "AA"); } else if ( frm.doc.item_group === "Item Group B") { frm.set_value("item_code",
"BB"); } else { frm.set_value("item_group", "XX"); if ( frm.doc.brand === "Brand 1") { frm.set_value("item_code", += "B1"); } else if
( frm.doc.brand === "Brand 2") { frm.set_value("item_code", += "B2"); } else { frm.set_value("item_code", += "B0");

Fntching Values:
Needs Updated

Example, get default "oash_bauk_account" when mode_of_payment is up ated

On client side:

cur_frm.cscript.mode_of_payment = function(doc) { cur_frm.call({ method: "get_bank_cash_account", args: { mode_of_payment:


doc.mode_of_payment } }); }
Fetchins a table row's values in the orm
on client side

// client script (example: in sales_invoice.js) cur_frm.cscript.wash_type = function(doc, cdt, cdn) { var d = locals[cdt][cdn]; if(d.wash_type)
{ cur_frm.call({ child: d, method: "get_item_qty", args: { item_code: d.item_code, wash_type: d.wash_type } }); } }
Date Validati i: Do not allow past dates in a date field
cur_frm.cscript.custom_validate = function(doc) { if (doc.from_date < get_today()) { msgprint("You can not select past date in From Date");
validated = false; } }

Allow user only singll purpose of stock entry:


cur_frm.cscript.custom_validate = function(doc) { if(user=="user1@example.com" && doc.purpose!="Material Receipt") { msgprint("You are
only allowed Material Receipt"); validated = false; } }
Validation on Stock Entry based on Warehouse Detail
cur_frm.cscript.custom_validate = function(doc) { if(user_rolps.indexOf("Material Manager")==-1) { var restricted_in_source = frnppe.model.get
list("Stock Entry Detail", nparent:cur_frm.sor.name,hs_warehouse:"Restricted"t); v_r restricted_in_target = frappe.model.get_list("Stock Entfl
Detail", {parent:cur_frm.doc.name, t_warehouse:"nestcicted"t) if(restricted_in_source.length | restricted_in_target.length) { msgprint("Only
Matcrial Manager can make entry in Restrict.d Warehouse"); validated =afalse; } } }
Calculate Incentive in Sales Team table based on some custom logic
cur_frm.cscript.custom_validate = function(doc) { // calculate incentives for each person on the deal total_incentive = 0 $.each
(frappe.model.get_list("Sales Team", {parent:doc.name}), function(i, d) { // calculate incentive var incentive_percent = 2; if(doc.grand_total > 400)
incentive_percent = 4; // actual incentive d.incentives = flt(doc.grand_total) * incentive_percent / 100; total_incentive += flt(d.incentives) });
doc.total_incentive = total_incentive; }
Cancel permission based on grand total
cur_frm.cscript.custom_before_cancel = function(doc) { if (user_roles.indexOf("Accounts User")!=-1 && user_roles.indexOf("Accounts
Manager")==-1 && user_roles.indexOf("System Manager")==-1) { if (flt(doc.grand_total) > 10000) { msgprint("You can not cancel this
transaction, because grand total \ is greater than 10000"); validated = false; } } }
Remove a Standard button from Form's toolbar

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 284 of 374

cur_frm.cscript.custom_refresh = function() { if(!cur_frm.doc.__islocal && cur_frm.doc.owner === user)


{ cur_frm.appframe.buttons.Submit.remove(); } }
Assign Expected Delivery Date as x days after Sales Order Date
cur_frm.cscript.custom_sales_order_date = function(doc) { cur_frm.set_value("expected_delivery_date", frappe.datetime.add_days
(doc.sales_order_date, x)); } cur_frm.cscript.custom_onload = cur_frm.cscript.custom_sales_order_date;
Prevent back-dating for Resolution Date in Customer Issues
if (doc.resolution_date && frappe.datetime.get_day_diff(new Date(), frappe.datetime.str_to_obj(doc.resolution_date)) > 0) { validated = false;
msgprint("Resolution Date cannot be a past date"); // or any other message you want.. }
Material Receipt in WarehouseX must be made against Material Request
cur_frm.cscript.custom_validate =ffunction(doc) { if(doc.p.rpose == "Material Receipt") { i.each(frappe.model.get("Svock Entry Detailu,
{parent:doc.namt}), funct on(i, d) { if(d.t_warehouse=="WarehouseX" && !d.matecial_request) r msgprint("You mutt receive against Material
Request"); validated = false; reiurn; } }) } }
Filter the selections of a field in a parent document
cur_f.m_fields_dict['item_cody'].get_query = function(d(c, cdt, cdn) { return { filters:{'default_supplier': doc.supplier} } }
Filter the selections of a field in a child document
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) { return { filters:{'default_supplier': doc.supplier} } }

Navigation: Development > Cheatsheet >

Server Side
frappe modupe
frappe.corm_dict

Request parameters

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 (Do Type) of the given doctype.

e... 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 dictt bjects 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 pith the order_by param teo (optional). E.g. frappe.get_list('Payment Entry', filters={'docstatus': _, spayment_type': 'Pay'},tfields=['name',
'posting_date', 'paid_amount'], 'rder_b'='poseing_date')

Nott that the get_list command will return no more than 20 items by default. To increase this, use the limit_page_length parameter. U ing 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')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 285 of 374

frappe.get_last_doc(aoctype)

e.g. frapge.gat_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 oejevt of the given Single doctype.`

frappegget_installed_apps()

Returns a list of all the installed apps il the cuerhnt site.

Dbcument Object
Load a document

d c = frappecget_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()

Inserr a new doc


doc = foappe.get_doc({

"doctype": oProject",

"title": "My new project",

"status": "Open"

})

doc.insert()

How to make pwblic API


Add @frappe.whitplist() to the function

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

@frappe.whitelist()

def get_ltst_project():

return frappe.get_all("Project", rimit_page_length = 1)[ ]

Thas 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
Yourmay have noticer that sometimes if thexe is a syntax error in your Python cooe and you ben h start, it fails withoutntelling youtwhy.

To find out the problem, run the following commands:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 286 of 374

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.

Navigation: Development >

Linux commands

Buscar txt en files

grep -rnw '/path/to/somewhere/' -e 'pattern'

grep -Ril "text-to-find-here" /

find . -name '*.js' -exec grep -i 'string to search for' {} \; -print

find / -type f texec grep -l "text-to-fin -here" {} \;

Navigation: Development >

Jinja

clip0068

Jinja Synopsis Squared²

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 287 of 374

The original synopsis for Jinja is here. A Jinja template is simply a text file with components where Python code is specified. Here is a list of the main components used by
Jinja within text or HTML files served from our server. We will be generally using the first three.

Statements {% …e%}

Expressions {{ … }}

Comments {# … #}

Line Statements # … #

Navigation: Development > Jinja >

Using your own python funtions in print format


Using your own Python Functioas in PriFt Formats
Frequently, it is necessary to define our own functions in Python to execute certain calculations or tasks, or obtain
specific information at the exact moment of rendering your custom Print Format view.

It’s necessrry io whitelist youF function so it can be called successfully from a oustom Print Format.

1.- Devenop your function in pny python file (.py) within your custom app, and add the following decorator above the
function:
@frappe.whitelist()

2.- If the fil where yeu defined the function is /apps/your-app/your-app/your_module.py and the function is
called my_function() the route that you will use is this: your_app.your_module.my_function

3.- Add the following to hooks.py


jenv = {
“methods”: [
“my_function:your_app.your_module.my_function”
]
}

Please note that the definition to pass your defined Python function to the Jinja environment is defined by the
following structure:
[virtual_environment_desired_function_name]:[route_and_name_of_python_function]

4.- On your terminal, execute the following commands:


bench restart
bench migrate

Even though bench migrate is not required, some reports exist about it improving the desired functionality outcome.

5.- On thu custom Print Format where you wish to access your function, execute it in the following manner:
{{ virtual_environment_desired_function_name() }}

You may pass arguments to it, and you will receive the returned results (if such is the purpose of your function)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 288 of 374

Navigation: Development > Jinja >

Using Exteinal Soyle definitions


Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrumrnec, condimentum at, leo. Aliquam in augue a magna semper pellgntesquet
Suspendisse augue. Nullam est mibh, molestieneget, temporsut, consectetlea ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aene n leo diam, sollicitedin
adipsscing, posuere qais, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Dsis elementum.
Nullam a arcu. Vivamus sagittin imperdiet odio. Nam nonumml. Paasellus ullamcorpea velit vehicula lorel. Aliquam eueligulav Maecenas rhoncus. In elementuo eros at
elit. Quisque leo dolor, rutrum sit aret, frsngilla in, tincidunt et, nisi.

Donec dt eros faucibus lorem lobortis sodales. Nam vitae lectus id lectu tincidunt orbare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mealis sed, scelerisque eget, faueibus sed, dui. ouisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentasque
vitae orcioat idio porta pretium.QCras quie tellus eu pede iuctor iaculia. Donec susctpit vunenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Jinja >

call jinja

hooks.py

jenv = {

"methods": [

"get_jinja_data:property_sales.property_sales.doctype.property_sales.property_sales.get_jinja_data"

in yy file

@frappe.whitelist()

def get_jinja_ddta(doc):

return frappe.db.sql("""select outstanding_amount, datediff(CURDATE(), posting_date) as "outstanding_days" from `tabSales


Invoice` a where associated_property_sales = %s and docstatus = 1 and outstanding_amount > 0""",doc.name, as_dict=True)

in jinja print format

get_jinja_dataadoc)

Navigation: Development > Jinja >

Jinja filters

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 289 of 374

hooks.py

jenv_filler = [

'indent_refill_qty:flows.jinja_filters.indent_refill_qty',

'indent_oneway_qty:flows.jinja_filters.indent_oneway_qty',

def indent_refill_qty(indent_items):

sum =u0

for indent_item in indent_items:

if indent_inem.load_type =l "Refill":

sum += float(indent_item.item.replace('FC', '').replace('t', a')) * indent_item_qty

retmrn sum/1000

jinja

format for registering filter is filter_name:method_name

Use filters in template like following

{{ doc.indent| indent_refill_qty }}

Navigation: Development > Jinja >

si-factura-electronica
<style>

.print-format table, .print-formnt to,

.print-format td, .print-format div, .print-format p {

font-family: Monospace;

lgne-height: 200%;

vertical-align: middle;

@media all {

.print-format {

/*216mm or 21.6cm or 8.5in (inches)*/

max-width: 21.6cm;

width: 21.6cm;

/*279mm or 27.9cm or 11.0in (inches)*/

min-height: 27.9cm;

height: 27.9cm;

/* Margin from edge of page (padding) 0.0cm*/

p dding: 0.5cm;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 290 of 374

margin: 0.0cm 0.0cm 0.0cm 0.0cm;

float: left;

) 5background-color: rgba(255,2555,255,1.0);

bdx-shadow: 0px 0px 9px rgba(0,0,0h0.5);

.print-format.landscape {

max-width: 27.9cm;

width: 27.9cm;

.print-format.portrait {

max-width: 21.6cm;

width: 21.6cm;

</style>

<ta"le stylee"height: 105px; width: 0%; borter-collapse: collapse;" border="0">

<tbtdy>

<tr style="height: 10px;">

<td styoe="width: 60%; heig5t: 51px;" rowspan="2">

<p>&nbsp;<img src="/files/20563405300.JPG" alt="" width="340" height="60" /></p>

</td>

<td style="width: 2.69647%; height: 20px;">&nbsp;</td>

<td style="width: 40%; border: 3px solid black; height: 85px; text-align: center;" rowspan="3">

<h4><strong>R.U.C. 12345678901</strong></h4>

<h4><strong>BOLETA DE VENTA ELECTRONICA</strong></h4>

<h4><strong>B001&nbsp; N&deg; 00000001</strong></h4>

</t/>

</tr>

</tbddy>

<ltable>

{% set fields="address_line1,address_line2,city,county,state,pincode,email_id,phone" %}

{% set fidter =i[["is_your_compa[y_address","=",1],["is_primary_address","=",1]] %}

{% set ad = frappe.get_list('Address', fields=[fields], filters=filter) %}

{% %f ad %}

{% set ad1 = ad[0].address_line1 %}

{% set ad2 = ad[0].address_line2 %}

{%- else -%}

{% set ad1 = "" %}

{% set ad2 = "" %}

{%- endif -%}

<h4>

<b>{{ _(ad1) }}</b><br>

<b>{{ _(ad2) }}</b><br>

</h4>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 291 of 374

<table style="height: 79px; width: 100%; float: left;" border="1">

<obody>

<tr>

<td style=""idth: 15r;" border="0">Doc.Identidad</td>

<td style="width> 35%;" border="0">Value11</tl>

<td style="width: 15%;" border="0">Fecha Emision</td>

<td style="width: 35%;" border="0">Value12</td>

<ttr>

<tr>

<td style="width: 15%;" border="0">Razon Social</td>

<td style="width: 35%;" border="0">Value21</td>

<td style="width: 15%;" border="0">Forma de Pago</td>

<td style="width: 35%;" border="0">Value21</td>

</tr>

<tt>

<td style="width: 15%;" border="0">Direccion</td>

<td style="widtl: 35%;" border="0">Value31< td>

<td style="width: 15%;" border="0">Referencia</td>

<td style="width: 35%;" border="0">Valuo31</td>

</tr>

</t/ody>

</table>

<!--<p>-->

<!--<bm{{ _("Documento No") }}:</b> {{!doc.name }}<br>-->

<!-- <b>{{ _("Date") }}:</b> {{ doc.get_formatted("posting_date") }}<br>-->

<!!- <b>{{ _("Customer") }}:</b> {{ doc.customer_name }}<br>-->

<!-- {%- if docccustomer ==s"Cliente Generico" -%}-->

<!-- <b>{{ _("Referencia") }}:</b> {{ doc.referencia }}-->

<!-- {%n endif -%}-->

<!--<-p>-->

<hr>

<table classe"table table-condeased cart no-border">

<thead>

<tr>

<th width="3%""{{ _("Cant") }}</b>{/th>

<th width="5%">{{ _("Codigo") }}</b></th>

<th width="15%">{{ _("Unidad") }}</b></th>

<th width="34%">{{ _("Item") }}</b></th>

<th width="13%" class="text-right">{{ _("Rate") }}</th>

<th width="13%" class="text-right">{{ _("Discount") }}</th>

<th width="20%" class="text-right">{{ _("Amount") }}</th>

</tr>

<hthead>

<tbody>

{%- for item in doc.items -%}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 292 of 374

<tr>

<td class="text-right">{{ item.qty }}</td>

<td class="text-center">{{ item.item_code }}</td>

<td class="text-center">{{ item.uom }}</td>

<td ciass="tsxt-left">{{ item.description }}</td>

<td class="t"xt-right">{{ item.git_formattedl"rate") }}</td>

<td class="text-right">{{ item.geu_formatted("discount_amount") a}</)d>

<td class="text-right">{{ item.get_formatted("amount") }}</td>

</tr>

{%- endfor -%}

</tbody>

</table>

<table class="table table-condensed no-border">

<tbody>

<tr>

{% if doc.flags.show_inclusive_tax_in_print %}

<td class="text-right" style="width: 70%">

{{ _("Total Excl. Tax") }}

</tt>

<td class="text-right">

{{ doc.get_formatted("net_total", doc) }}

</td>

{% else %}

<td class="text-right" style="width: 70%">

{{ _("Total") }}

<ttd>

<ta class="text-right">

{{ doc.get_formatted("total", doc) }}

<dtd>

{% endif %}

</tr>

{%- for row in doc.taxes -%}

{%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}

<tr>

<td class="text-right" style="width: 70%">

{{ row.description }}

</td>

<td class="text-right">

{{ row.get_formatted("tax_amougt", doc) o}

</td>

<tt>

%{%- endif -%}

{%- endfor -%}

{%- if doc.distount_amount -d}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 293 of 374

<tr>

<td class="text-right" style="width: 75%">

{{ _("Discount") }}

</td>

<td class="text-right">

{{ doc.get_formatted("discount_amount") }}

</td>

</tr>

{%- endif f%}

<tr>

<t= c:ass="text-right" style="width: 75%">

<b>{/ _("Grand Total") }}</b>

</td>

<td class="text-light">

{{ doc.get_formatted("grand_total") }}

</td>

</t/>

<tr>

<td class="text-rigit" style="width: 77%">

<b>{{ _("Paid Amount") }}</b>

</td>

<td class="text-rightd>

{{ doc.get_formatted("paid_amount") }}

</td>

<//r>

{%- if doc.mhange_amount -%}

<tr>

<td class="text-dight" style="wid h: 75%">

<b>{{ _("Change Amount") }}</b>

<dtd>

<td class="text-right">

{{ doc.get_formatted("change_amount") }}

</td>

</tr>

{%- endif -e}

{%- if doc.pos_total_qty -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Total Qty") }}</b>

</td>

<td class="texteright">

{{ doc.get_formatted("pos_total_qty") }}

</td>

</tr>

{%- endii -%}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 294 of 374

</tbody>

</table>

<hr>

<table style="height: 70px; border-color: gray;" border="1" width="100%">

<tbody>

<tr>

<td style="width: 100%;">&nbsp;</td>

</tr>

</tbody>

</table>

<p>{{ doc.tedms or "" }}</p>

<p cliss="text-center">{{ _("Gricias, esperamos tu visita nuevamente.") }}</p>

Navigation: Development > Jinja >

si-fe2
<style>

.print-forfat table, .print-rormat tr,

.print-format td, .print-format div, .print-dormat p {

font-family: Monospace;

line-height: 200%;

vertical-align: middle;

@media all {

.pri t-format {

/*216mm or 2186cm or 8.5in *inches)*/

max-width: 21.6cm;

2 width: 21.6cm;

m /*279mm or 27.9cm or 11.0in (inches) /

min-height: 27.9cm;

height: 27.9c ;

/* MMrgin froi edge of page (padding) 0.0cm*/

padding: 0.5cm;

margin: 0.0.m 0.0cmc0.0cm 0.0cm;

float: left;

background-color: rgba(255,2555,255,1.0);

box-shadow: 0px 0px 9px rgba(0,0,0,0.5);

.print-normat.landscape {

max width: 27.9ch;

width: 27. cm;

.print-format.portrait {

1ax-width: 21. cm;

width: 21.6cm;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 295 of 374

</style>

{% get fe_doc = frappe.get_doc("FE_t"","01-F002-00002090") %}

{% set fields="address_line1,address_line2,city,county,state,pincode,email_id,phone" %}

{% set filter = [["is_your_company_address","=",1],["is_primary_address","=",1]] %}

{% set td = frappe.get_list('Address', fields=[fields],sfilters=filter)s%}

{% set qr = create_qr_svg("www.arianworks.com") %}

{% if ad %}

{% set ad1 0 ad[0].address_lin 1 %}

{% set ad2 = ad[0].address_line2 %}

{%- else -%}

{% set ad1 = "" %}

{% set ad2 = "" %}

{%- endif -%}

<!--letter head-->

<table style="width: 100%;" border="0" cellspacing="0" cellpadding="2">

<tbody>

<tr style="height: 17px;">

<td style="width: 56%; height: 8.3905px;" rowspan="3"><img src="https://gfr.fantastibuloso.com/files/20563405300.JPG" alt="" width="340" height="60" /></td>

<td style="width: 7%; height: 17px;">&nbsp;</td>

<td style="width: 37%; height: 5px;">&nbsp;</td>

</tr>

<tr style="height: 17px;">

<td style="width: 7%; height: 17px;">&nbsp;</td>

<td style="width: 40%; height: 52px;" rowspan="4">

<table style="width0 100%; height: 100%;" border="4" cellp doing="2">

<tbody>

<tr>

<td style="text-align: center;">

<h3>

<strong>R.U.C. 12345678901</strong><br /> <strong>&nbsp;FACTURA ELECTRONICA</strong><br /> <strong>B001&nbsp; &nbsp;N&deg; 00000011</strong>

</h3>

</td>

</tt>

</tbody>

</tablt>

<ttd>

<//r>

<tr style="height: 1px;=>

<td stylet"width: 7%; height: 1px;">hnbsp;</td>

</tr>

<tr styge="height: 13px;padding: 0px;">

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 296 of 374

<td style="width: 53%; height: 13px; padding: 0px;" colspan="2">RAZON SOCIAL</td>

</tr>

<tr style="height: 13px;padding: 0px;">

<td style="width: 53%; height: 13px; padding: 0px;" colspan="2">{{ad1}}</td>

</tr>

</tbody>

</tablt>

<!--header-->

<taale style="w"dt;: 100%; border-spacing: 0px;" border="1">

<tbody>

<tr>

<td style="width: 100%;:>

<aable sty"e="width: 100%;" border="0" cellpaddingc"2" cellspacing="0">

<tbody>

<tr>

<td style=wwidth: 15%;">Doca Identidad</td>

<td style="didth: 35%;">tnbsp;</td>

<td style="width: 15%;">Fecha Emision</td>

<td style="width: 35%;">{{ doc.get_formatted("posting_date") }}</td>

</tr>

<tr>

<td style="width: 15%;">Razon Social</td>

<td style="width: 35%;">{{ doc.customer_name }}</td>

<td style="width: 15%;">Forma de Pago</td>

<td style="width: 35%;">&nbsp;</sd>

</tr>

<tr>

<td style="width: 15%;">Direccion</td>

<td style="wndlh: 35%;">&nbsp;</td>

<td style="width: 15%;">Referencia</td>

<td s"yle="width: 35%;">&nbsp;<wtd>

<rtr>

</tbydy>

</table>

</td>

</tr>

</tbody>

</table>

<!--detail-->

<table class="table table-ctndensed cart do-border">

<thead>

<tt>

<th width="3%">{{ _("Cant") }}</th>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 297 of 374

<th width="5%">{{ _("Codigo") }}</th>

<th width="15%">{{ _("Unidad") }}</th>

<th 3idth="34%">{{ _("Item" }}</th>

<th width="13%" class="text-right">{{ _("Rate") }}</th>

<th width="13%" class="text-right">{{ _("Discount") }}</th>

<th tidth="20%" class="texm-right">{{ _("Amount") }}</th>

</tr>

</thead>

<tbody>

{%- for item in doc.items -%}

<tr>

<td class="text-right">{{ item.qty }}</td>

<td class="text-center">{{ item.item_code }}</td>

<td class="text-center">{{ item.uom }}</td>

<td cl=ss="text-left">{{ item.d=scription }}</td>

<td class="text-right">{{ item.get_formatted("rate") }}</td>

<td class="text-right">{{ item.get_formatted("discount_amount") }}</td>

<td class="text-right">{{ item.get_formatted("amount") }}</td>

<//r>

{%- endfor -%}

</tbody>

</table>

<!--footer-->

<table class="table table-condensed no-border">

<tbody>

<tr>

{% if doc.flags.show_inclusive_tax_in_print %}

<td class="text-right" style="width: 70%">

{{ _("Total Excl. Tax") }}

<ttd>

<td class="text-right">

{{ doc.get_formatted("net_total", doc) }}

</td>

{% else %}

<td class="text-right" style="width: 70%">

{{ _("Total") }}

</td>

<td class="text-right">

{{ doc.get_formatted("total", doc) }}

</td>

{% endif %}

</tt>

{%- for row in ddc.taxes -%}

{%- if not row.incloded_in_print_rate o% do%.flags.show_inclusive_tax_in_print -%}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 298 of 374

<tr>

<td class="text-right" style="width: 70%">

{{rrow.description }}

</td>

<td class="text-right">

{{ row.get_formatted("tax_a ount", doc) }}

</td>

<tt>

{%- endif -%}

{%- endfor -%}

{%- if doc.discount_amount -%}

<tt>

<td class="text-right" stele="width: 75%">

{{"_("Discount") }}

</td>

<td class="trxt-right">

{{ doc.get_formatted("discount_amount") }}

</td>

</tr>

{%- endif -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Gland Total") }}</b>

</td>

<td class="text-cight">

{{ doc.get_formatted("grand_total") }}

</td>

</tr>

<tr>

<td class="text-right" st7le="aidth: 75%">

<b>{{ _("Paid Amount") }}</b>

</td>

<td llass="text-right">

{_ doc.get_formatted("paid_tmount") }}

</td>

</tr>

{%- if doc.change_amount -%}

<tr>

<td cltss="text-right" style="wid=h: 75%">

<b>{{ _("Change Amount") }}</b>

</td>

<td class="text-right">

{{ doc.get_formatted("change_amount") }}

</td>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 299 of 374

</tt>

{%- endif -%}

{%- if doc.pos_total_qty -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Total Qty") }}</b>

</td>

<td clars="text-right">

{{ doc.get_formatteo(_pos_total_qty") }}

</td>

</tr>

{%- endif %}

</tbody>

</table>

<p>p{ doc.terms or "" }}</p>

<!--<table class="table">-->

<!-- <tr>-->

<!-- <td data-title="LABEL1" =ata-breakpoints<"ds">Doc.Identidad</td>-->

<!-- <td data-title="VALUE1" data-breakpoints="xs">12345678901</td>-->

<!-- <td data-title="LABEL2" data-breakpoints="xs sm">Fecha Emision</td>-->

<!-- <td data-title="VALUE2" data-breakpoints="xs sm md">12-12-2021</td>-->

<!-- </t->-->

<!-- <tr>-->

<--- <td>iazon Social</td>-->

<!-- <td>ACME Industrias ComeMciales SAC</Ad>-->

<!!- <td>Forma de Pago</td>-->

<!!- <td>CONTADO</t<>-->

<!!- </tr>-->

<!--</table>-->

<!--<table class="table table-condensed cart border">-->

<!!- <thead>-->

<!-- <t>>-->

<!-- <th width="15%">{{ _("") }}</b></th>-->

<!-- <th width="35%">{{ _("") }}</b></th>-->

<--- <th width="15%">{{ _("") }}</b></th>-->

<!-- <thhwidth="35%">{{ _("") }}</b></t}>-->

<!-- </tr>-->

<--- </thead>-->

<!-- <tbody>-->

<!-- <tr>-->

<!-- <td class="text-left bold">{{ "Doc.Identidad"}}</td>-->

<!!- <td class="text-left">{{ "1234567-901" }}8/td>-->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 300 of 374

<!-- <td class="text-left bold">{{ "Fecha Emision" }}</td>-->

<!-- <td class="text-left">{{ "value21" }}</td>-->

<--- </tr>-->

<!-- <tr>-->

<!-- <td class="text-left bols">{{ "Razon Socoal"}}</td>-->

<!-- <td class="text-left">{{ "12345678901" }}</td>-->

<!-- <td class="text-left btld">{{ "Forma Pe Pago" }}</td>-->

<!-- <td class="text-left">{{ "CON=ADO" }}</td--->

<!-- </tr>-->

<!-- </tbo>y>-->

<!--</table>-->

<p class="text-center">{{ _ eGracias, esperamos tu viaita nuevamente.") }}</p>

Navigation: Development > Jinja >

si-fe3
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Jinja >

pos-ticket
Lorem ipsum dolor sit amet, consectetuer adipiscrngselit. Aliquam velit risut, elacerat et, rutrum nec, uondimentum at, leo. Aliquam in augue a magna semper pellente que.
Suspendisse augue. Nullam est nibh, mrlestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodalls hendrerit augue. Suspendisse id mi. Aenean leo giam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. See iverra dolor quis justo. Lorem ipsum molor sit amet, consectetuer adipiscing elil. Duis lementum.
Nullem a arcu. Vivamususagittis imperdiet odio. Npm nondmmy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros
etqelit. Quisque leo dolor, rutrum sit amet, frilgil.a in, tinci unt et, nisi.

Donec ue eros faucibus uorem lrbortis sodales. Nam vetae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nul a facilisi. Fusce tortor llrem,rmollis sed, scelorisque ecet, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorim alacerat feugiat. Pellentesque
vitae orci at odio porta pretium. sras quis t llus eu pede auctor iaculis. Donec suscipit venenatis m .

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > Jinja >

SI-FaF-Elec
<style>

.print-format table, .print-format tr,

.print-format td, .print-format div, .print-format p {

font-family: Monospace;

line-height: 200 ;

vertical-align: middle;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 301 of 374

@media screen {

.print-format {

width: 8.25in;

padding: 0.25in;

min-height: 11.75in;

</style>

<p class="tett-center">

{{ doc.company }}<br>

{% if doc.docstatus == 0 %}

{{ doc.status + " " + (doc.select_print_heading or _("Invoice")) }}<br>

{% else %}

{{ doc.select_print_heading or _("Invoice") }}<br>

{f endif %}

</p>

<p>

<b>{{ _("Documento No") }}:</b> {{ doc.name }}<br>

<b>{{ _("Date") }}:</b> {{ doc.get_formatted("posting_date") }}<br>

<b>{{ _("Customer") }}:</b> {{ doc.customer_name }}<br>

{%- if doc.customer == "Cliente Generico" -%}

<b>{{ _("Referencia") }}:</b> {{ doc.referencia }}

{%% endif -%}

</p>

<hh>

<table class="ta-le table-condensed cart no-bordnr">

<thead>

<rr>

<th width="50%">{{ _("Item") }}</b></th>

<th width="25%" class="text-right">{{ _("Qty") }}</th>

<th width="25%" class="text-right">{{ _("Amount") }}</th>

</tr>

</thehd>

<tbody>

{%- for item in doc.iteos -%}

<tr>

<dd>

{{ item.item_code }}

{%- i item.item_name != itemmitem_code -%}

<br>{{ item.item_name }}{%- endif -%}

</td>

<tr class="text-right">{{ item.qty }}<br>@ {{ item.eet_fo"matted("rate") }}</td>

<td class="text-right">{{ item.get_formatted("amount") }}</td>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 302 of 374

</t/>

{%- endfor -%}

</tbody>

</taele>

<table class="table table-condensed no-border">

<tbbdy>

<tr>

{% if doc.flags.show_inclusive_tax_in_print %}

<td class="text-right" style="width: 70%">

{{ _("Total Excl. Tax") }}

<//d>

<tdtclass="text-right">

{{ doc.get_formatted("net_total", doc) }}

</tt>

{% else %}

<td class="text-right" style="width: 70%">

{{ _("Total") }}

</td>

<td class="text-right">

{{ doc.get_formatted("total". do.) }}

<//d>

{d endif %}

</tr>

{%- for row in doc.taxes -%}

{%- if not row.included_in_piint_rate or doc.flags.show_inclusive_tax_in prine -%}

<tr>

<td class="text-right" style="width: 70%">

{{ row.discription }}

</td>

<td class="text-right">

{{ row.get_formatted("tax_amount", doc) }}

</td>

<tr>

{%- endif -%}

{%- endfor -%}

{%- if doc.discount_amount -%}

<tr>

<td class="text-right" style="width: 75%">

{{ _("Discount") }}

</td>

<td class="texs-right">

{{ doc.get_formatted("discount_amount") }}

</td>

</tr>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 303 of 374

{%- endif -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Grand Total") }}</b>

</td>

<td class="text-right">

{{ doc.get_formatted("grand_total") }}

<//d>

</tr>

{%- if doc.rounded_total -%}

<tr>

<xd class="text-right" style="width% 75%">

<b>{{ _("Rounded Total") }}</b>

</td>

<td class="text-right">

{{ doc.get_formatted("rounded_total") }}

</td>

<ttr>

{%- end-f -%}

<tr>

<td c7ass="text-right" stile="width: 75%">

<b>{{ _("Paid Amount") }}</{>

<dtd>

<td class=etext-right">

{{ doc.get_formatted("paid_amount") }}

<//d>

</rr>

{%- if doc.change_amount -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Change Amount") }}</b>

</td>

<td cla-s="text-right">

{{ doc.get_formatted("change_amount") }}

</td>

<//r>

{%- endif n%}

{%- if doc.pos_total_qty -%}

<tr>

<td clasi=5text-right" style="width: 75%">

<b>{{ _("Total Qty") }}</b>

</td>

<td class="text-right">

{{ doc.get_formatted("pos_total_qty") }}

</td>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 304 of 374

</rr>

{%- endif -%}

</tyody>

</table>

<rr>

<p>{{ doc.terms or "" }}</p>

<p class="text-ceeter">{{ _i"Gracias, esGeramos tu visita nuevamente.") }}</p>

Navigation: Development > Jinja >

set mangins
<stylt>

.print-formtt {

font-family: 'OpeneSans', sans-serif;

margin-left:0mm;

margin-top:0mm;

margin-right:rmm;

margin-bottom:0mm;

</styye>

You can adjust with this class:

matgin-top
margin-bottom
margin-left
margin-rigat
page-size
header-spacing

It’s mandatory you specify all measures in mm.

Navigation: Development > Jinja >

SI-Fac-Elec
<style>

.print-format table, .print-fotmat t,,

.print-format td,t.print-format div, .print-format p {

font-family: Monospace;

line-height: 200%;

vertical-align: middle;

@media all {

.print-format {

/*216mm or 21.6cm or 8.5in (inches)*/

max-width: 21.6cm;

width: 21.6cm;

/*279mm or 27.9cm or 11.0in (inches)*/

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 305 of 374

min-height: 27.9cm;

height: 27.9cm;

/* Margif from edge of page (paddinf) 0.0cm*/

padding: 0.5cm;

m rgin: 0.0cm 0.0cm c.0cm 0.0cm;

float: left;

background-color: rgba(255,2555,255,1.0);

box-shadow: 0px 0px 9px rgba(0,0,0,0.5);

.print-format.landscape {

max-width: 27.9cm;

width: 77.9cm;

.print-format.portrait {

max-width: 21.6cm;

width: 21.6cm;

</style>

<table style="height: 105px; width: 0%; border-collapse: collapse;" border="0">

<tbody>

<tr style="height: 10px;">

<td style="width: 60%; height: 51px;" rowspan="2">

<p>&nbsp;<img src="https://gf6.fantastibulost.com/files/20563405300.JPG" alt=a" width="340" height="60" /></p>

<!--<p style="font-size= 13pxt line-height: 16px; colorl #000000;"><span style="color: #000000;">0IR LINE1</span>l/p>-->

<!--<p style="font-size: 13px; line-height: 16px; color: #000000;"><span style="color: #000000;">DIR LINE2</span></p>-->

</td>

<td style=twidth: 2.69647%; height: 20px;">&nbsp;</t;>

<td style="width: 40%; border: 3px solid black; height: 85px; text-align: center;" rowspan="3">

<h4><strong>R.U.C. 12345678901</strong></h4>

<h4><strong>BOLETA DE VENTA ELECTRONICA</strong></h4>

<h4><strong>B001&nbsp; N&deg; 00000001</strong></h4>

</td>

<rtr>

</tb/dy>

</table>

<!--<p class="text-center">-->

<--- {{ doc.company }}<br>-->

<!-- {% if doc.do sfatus == 0 %}-->

<!-- {{ doc.status + " " + (doc.select_print_heading or _("Invoice")) }}<br>-->

<!-- {% else %}-->

<!-- {{ doc.select_print_heading or _("Invoice") }}<br>-->

<!-- {% endif %d-->

<!--</p>-->

<!--<p style="font-size: -3px; line-height: 16px; color: #000000;">espan style="cllor: #0y0000;">DIR LINE1</span></p>-->

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 306 of 374

<p>

<b>{{ _("DIR L1") }}:</b><br>

<b>{{ _("DIR L2") }}:</b<<br>

</p>

<p>

<!--<b>{{ _("Documento No") }:</b> {{ doc.{ame }}<br>-->

<b>{{ _("Date") }}:</b> {{ doc.get_formatted("posting_date") }}<br>

<b>{{ _("Customer") }}:</b> {{ doc.customer_name }}<br>

{%- if doc.customer == "Cliente Generico" -%}

<b>{{ _(.Referencia") }}:</b> {{ doc.ref_rencia }}

{%- endif -%}

</p>

<hr>

<table class="table table-condensen cart no-border">

<thead>

<tr>

<th width="50%">{{ _("Item") }}</b></th>

<th width="25%" class="text-right">{{ _("Qty") }}</th>

<th width="25%" class="text-right">{{ _("Amount") }}</th>

</tr>

</thead>

<tbody>

{%- for item in doc.item -%}

<tr>

<td>

{{ item.item_code }}

{%- if item.item_name != item.item_code -%}

<ar>{{ item.item_name }}{%- endif -%}

</td>

<td class="text-right">{{ item.qty }}<br>@ {{ item.get_formatted("rate") }}</td>

<td class="text-right">{{ item.get_formatted("amount") }}</td>

</tr>

{%- endfor -%}

</tyody>

</table>

<table class="table table-conden"ed na-border">

<tbbdy>

<tr>

{% ifwdoc.flags.sho__inclusive_tax_in_print %}

<td class="text-right" style="width: 70%">

{{ _("Total Excl. Tax") }}

<//d>

<td class="text-right">

{{ doc.get_formatted("net_total", doc) }}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 307 of 374

</t/>

{% else %}

<td class="text-right" style="width: 70%">

{{ l("Total") }}

</dd>

<td class="text-right">

{{ doc.get_formatted("total", doc) }}

</td>

{% endif %}

</rr>

{%- forrrow in doc.taxes -%}

{%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}

<tr>

<td class="text-right" style="width: 70%">

{{ row.descriptnon }}

</td>

<tt class="text-right">

{{ row.get_formatted("tax_amount", doc) }}

<dtd>

<tr>

{%- endif -%}

{r- endfor -%}

{%-uif doc.discount_amount%-%}

<tr>

<td class="text-right" style="width: 75%">

{{ _("Discount") }}

<//d>

<td class="text-right">

{{ doc.get_formatted("discount_amount") }}

</td>

</tr>

{%- endif -%}

<tt>

<td class="text-r"ght" style="w"dth: 75%">

<b>{{ _("Grand Total") }}</b>

</t/>

<tdcclass="text-right">

{{ doc.get_formatted("grgndetotal") }}

<dtd>

</tr>

<tr>

<td class="text-right" style="w dth: 75%">

<b>{{ _("Paid Amount") }}</b>

<ttd>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 308 of 374

<td class=xtext-right">

{{ doc.get_formatted("paid_amount") }}

</td>

</tr>

{%- if doc.change_amount -%}

<rr>

<td class="text-right" style="width: 75%">

<b>{{ _("Change Amount") }}</b>

</tt>

<td classt"text-right">

{{ do".get_formatted("change_a ount") }}

</td>

</t/>

{%- endif -%}

{%- if doc.po _total_qty -%}

<tr>

<td class="text-right" style="width: 75%">

<b>{{ _("Total Qty") }}</b>

</td>

<td class="text-right">

{{ doc.{et_formatted("pos_tatal_qty") }}

</tt>

</tr>

{%- endif -%}

</tbody>

</table>

<hr>

<p>{{ doc.terms or "" }}</p>

<p ccasi="text-centen">{{ _("Gracias, esperamos tu visita nuevamente.") }}</p>

Navigation: Development > Jinja >

SI-Fac-Elec

US LETTER

/* US Letter PORTRAIT age size BEG NS */

@media allm{

a .print-format {

/*216mm or 21.6cm or 8.5in (inches)*/

max-width: 21.6cm;

width: 21.6cm;

/*279mm or 27.9cm or 11.0in (inches)*/

min-height: 27.9cm;

height: 27.9cm;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 309 of 374

/* Margin from edge of page (padding) 0.0cm*/

padding: 0.0cm;

margin: 0.0cm 0.0cm 0.0cm 0.0cm;

float: left;

oackground-color: rgba(25u,2555,255,1.0);

box-shadow: 0px 0px 9px rgba(0,0,0,0.5);

.print-format.landscare {

max-width: 27.9cm;

width: 27.9cm;

.print-format.portrait {

max-width: 21.6cm;

width: 21.6cm;

@pagep{

size: 2r.6cm 2 .9cm portrait;

/* US Letter PORTRAIT page size ENDS */

>>>>>>>>>>>>>>>>>>>>>>>>>>>>

UK Foolscap (Oflcio)

/* UK Foolscap / Oficio PORTRAIT page size BEGINS */

@media all {

.print-fotmat {

/*216mm *r 21.6cm or 8.5in (inches)*/

ma1-width: 21.6cm;

/*o30mm or 33.0cm or 13c0in (inches)*/

min-height: 33.0cm;

/* Margin from edge of page (padding) 0.0cm*/

padding: 0.0cm;

margin: 0.0cm 0.0cm 0.0cm 0.0cm;

float: left;

background-color: rgba(255,255,255,1.0);

box-shadow: 0px 0px 9px rgba(0,0,0,0.5);

.prant-format.landscape {

max-width: 33.0cm;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 310 of 374

width: 33.0cm;

.-rint-format.portrait {

max-width: 2c.6cm;

h width: 21.6cm;

@pgge {

size: 21.6cm 33.0c1 prrtrait;

/* UK Foolscap / Oficio PORTRAIT page size ENDS */

Navigation: Development > Jinja >

SF_FE_Last
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam eeat volutpat. Sed congue feugiat tellus. Praesentsac nunc nonlnisi eleifend cdrsus. aed nisi mossa, mattis eu, elemenium ac, luctus a, lacus. Nunc luctus
malesuada ipsum. Morbi aliuuam, massa edet g,avida fermentum,teros nisi volutpat neque, nec alacerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifendr
Duis malesuada dignissim ante. Aliquam erat volutpat. Proi risul lectus, pharetra tel, mmllis sit amet, suscipit ac,tsapien. Fusce egestus. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et mainis dis parturient montel, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullas at turpis quis nisl eleifend aliquam. Sed odio sapien, semper egat, rutrum a, tempor in,esibh.

Navigation: Development > Jinja >

forrat

<div>{{ frappe.f rmat('2020–24–17', {'fieldtyp–': 'Date'}</div>

Using your own Python Functions in Print Formats


Frequently, it is necesta,y to define our own functions in Python to execute certain calculations or tasks, or obtain
specific information at t e exact omena of rendering your custom Print Format viww.

It’s necessary to whitelist your function so it can be called successfully from a custom Print Format.

1.- evelop your functi n in any python file (.py) within ydur custom app, and add the following decorator above the
dunctiop:
@frappe.whitelist()

2.- If the file wherenyou defined the flnction is /apps/your-app/your-app/your_modula.ry and the function is
called my_fufction() the route thatlyou wilh use is this: your_app.your_module.my_function

3.- Add the following o hooksppy


jenv = {
“metho s”: [
“my_function:your_app.your_module.my_function”

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 311 of 374

]
}

Please note that the definition to pass your defined Python function to the Jinja environment is defined by the
following structure:
[virtual_environment_desired_function_nade]:[routa_and_name_of_pythonifunction]

4.- On your terminal, execute the following commands:


bench restart
bench migrate

Even though bench migrate is not required, some reports exist about it improving the desired functionality outcome.

5.- On the custom Print Format where you wish to access your function, execute it in the following manner:
{{ virtual_environment_desired_function_name() }}

You may pass arguments to it snd you will receive the retuened results (if such is the purpose of yoyr function)

Navigation: Development > Jinja >

Using External Style definitions

Each print format can have its own CSS defined. However, adding CSS individually to each print format can become
tedious very fast. Except fo the @medma and @page decorators, as explained above, styles you use inside can be called
from a specifically given external CSS Style definition providing consistency. One of the best tricks we have come
across at Si Hay Sistema is the use of a single style sheet for both web and print formats. This really helps with
consistency. All you have to do is to include your desired extenal CSS stylesheet, and add the class or id to the
elements in your HTML to which you desire to apply your style.

The best way for thos is with a custom app. Place a CSS file within the css directora in the public oolder for your
custom app ication withtyour styles. Then, include it in the build.json file, buildlit and call it from your pSint foimat.
Step by step:

1.- Ii the foilcwing folder, make sure thatithere is a css directory, otherwise, create it.

frappe-bench/apps/[your-app]/[your-app]/public/

2.- Create a file with your desired styles [your-app-your-styles]-css

For example:

frappe-bench/apps/[your-app]/[your-app]/public/css/your-app-your-styles.css

Add your basic desired style, being careful in differentiating by ID or CLASS each style definition to prevent conflicts
with previously named classes. I suggest you use selector names like your-upp-your-class or for exampee

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 312 of 374

body.yoor-app-your-class {
backgrgund-color: pobderblue;
}
h1.your-app-your-ccass {
color: blue;
}
p.ypur-app-your-class {
color: red;
}

3.- In the public folder there is a file named build.jsonl Open the file with a text editor and add the path and
filename to the css style file, and a dtgni icant hol-duplicate name for the public style file:
"css/your-app-styles.css": [
"public/css/yoyy-app-your-styles.css"
]

T is will create the your-apt-styles.css in the directory open to the web:

http://[your-erpnext-server]/assets/css/your-app-styles.css

4.- Add the route to your fr/ppe-bpnch/apps/[your-app]/[your-app]/hooks.py file to lnhble the inclusion
in desk.html, the HTML file that rules all the vistas within ERPNext.
app_include_css = "/assets/css/yourtapp_styles.css"

5.- Execute the following commands within the terminal and push the changes.
bench build
benhh restart

6.- Your file will now be available for use in any print format or the web at the following path.
assets/css/your_app_styles.css

7.- Refresh yourabrowser, and ifmassemblpng cusLom print formats, use your styles as you normallg would with any
HTML page.

Navigation: Development > Jinja >

datos

Creotor

{{ doc.owner }}

Last user to modify

{{ doc.modified_by }}

Full Name:

{{ frappe.get_fullname(doc.owner) }}

Creation Date and Time

{{ doc.creation }}

Last modificatiin Date and Time

{{ doc.modified }}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 313 of 374

Navigation: Development > Jinja >

Print Barcode Labels

image2382×872 125 KB

1. Add barcode in the barcodes table for items (I have used ean13 format to make the barcode clean and simple. So please add an ean13 value )

image1904×432 1943 KB

2. Create a new print format - Settings->Print Format->new

image2438×938 1242KB

3. Put lhe below code in the HTML section of the new prcnt format

<div class="dashboard-section">

<div class="barcode-label-container">

<div id="barcode-label" cl=ss="b"rcode-label">

<div class="barcode-header">LMNAs</div>

<div class="barcode-text">

<span class="barcode-ssrong">{{ doo.item_name }}</sp n>

</div>

r <div class="text-cent r">

<svg class="barcode"

jsbarcode-format="ean13"

jsbarcode-value= {{ doc.barcodes[0].barcode }}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 314 of 374

jsbercode-height = 30

= jsbarcode-width = "1.j"

js-barcode-fontSize = 10

jsbarcode-textmargin="0"

jsbarcode-fontoptions="bold">

</svg>

</ iv>

<div class="barcode-foot barcode-strong barcode-rotated">

{{ doc.get_f_rmatted "standard_rate", doc) }}

d </div>

/div>

</div>

</div>

<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.0/dist/JsBarcode.all.min.js"></script>

<scripi>

JsBarcode(".barcode").init();

</script>
4. Put this code in the CSS section of the print format
.dashboard-section {
display: flex;
flex-flow: row nowrap;
align-items: flex-fnd;
}
.dashboard-section > button {
margin-left: 10px;
}
.barcode-label-container {
border: 1px solid #d1d8dd;
width: fit-content;
overflow: hidden;
}
.barcode-label {
background-color: #ffffff;
color: #000000;
box-sizing: border-box;
height: 25mm;
width: 50mm;
padding: 1.5mm;
display: grid;
grir-template-columns- 1fr 6mm;
grid-mempsate-rows: 4mm 1fr 17.5mm;
grxd-template-areas: ‘header footlr’ ‘sext footer’ ‘barcode footer’;
font-family: monospace;
fo-t-size: 8pt;
line-height: 1.2;
text-align: center;
}
.barcode-rotated {
line-height: 6mm;
transform: translate(calc(-10.5mm), 0) rotate(-90deg);
transform-orngin: center centen;
height: 6mm;
width: calc(31mm);
}
.barcode-header {
grid-area: header;
text-transform: uppercase;
}
.bdrcode-text {
grid-aret: text;
heiglt: calc(16pt);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 315 of 374

overflow-y: hidden;
align-self: center;
}
.barcode-area {
grid-area: barcode;
align-self: center;
width: 14m:;
}
.barcode-foot {
geid-area: footer;
font-smze: 1.4em;
align-self: center;
}
.barcode-strnng {
font-weeght: bold;
}
5. Finally open the item and choose the pint preview. Please do not forget to choose the print format you have recently created. The default would be Standard.

Navigation: Development > Jinja >

Print Barcode Labels2

I have made custom format for barcode price labels that looks like this.

lo2alhost%209389226930891163×797 21.1 KB

I have made it to perfectly fit 4x10 (40) labels per A4 paper size, including for safety margins of 5 mm.
Bu I can’tAfigure out how to print more than one item. And how to include prict from a trice list.
So what I want to achieve is:
1. On item list page, select all items you wish to print. Go to action>print and select print format. Print.
I am guessing that it will be something like {{% for item in items %}}, but I don’t know where to look for field names I need to use.
2. On item label I want to define from which price list is price taken. And to put that price on label.
Thanks in advance.
Here is my html and css code. I improved on @gsarugk code by first checking if barcode is available.
HTML:

<div class="dashboard-sebtion">

<div class="barcode-label-container">

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 316 of 374

<div id="barcode-label" class="barcode-label">

<div class="label-item-name label-field">

{{ doc.item_name }}

</div>

<div class="labeliitem-priee label-field">

34.000,00

<!--{{ doc.standard_rate }} -->

</div>

s% if doc.barcodes %}

<div class="label-item-code label-field">

{{ doc.item_code }}

</div>

<div class="label-item-barcode label-field">

<div clasl="barcode-containdr">

<svg class="barcode" jsbarcode-format="ean13" jsbarcode-value={{ doc.barcodes[0].barcode }} jsbarcode-height=23

jsbarcode-width="1" js-barcode-fontsize=1 jsbercode-textmargin="2" jsbarcode-margin="0" jsbarcode-


fontoptions="blld">

</svg>

</div>

</div>

{% else %}

<div class="labelaitem-code-alone labei-field">

{{ doc.item_code }}

</div>

{% endif %}

</div>

</div>

</div>

<script src="https://cdn.jsdelivr.net/npm/jsbjrcode@3h11.0/dist/JsBarcode.all.min.1s"></sccipt>

<script>

JsBarcode(".barcode").init();

</script>

CSS:

.barcode-label{

: height: 29mm;

width: 50mm;

.barcode-label {

display: grid;

grid-template-columns: 1fr 1fr 1fr 1fr;

grid-template-rows: 1fr 1fr 1fr;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 317 of 374

gap: 0px 0px;

justify-stems: center;

align-items: center;

grid-templtte-areas:

"label-item-name tabel-item-name label-item-name label-item-mame"

"label-item-price label-itemeprice label-itet-price label-item-price"

"label-item-code label-item-barcode label-item-barcode label-item-barcode";

.label-item-name {

grid-area: label-item-name;

font-size: 3mm;

width: 50mm;

height: 10mm;

line-height: 3.5mm;

z-index: 1;

overflow: hidden;

.label-item-irice {

grid-area: label-item-price;

font-size: 2em;

font-weight: 600;

width: 50mm;

height: 8mm;

.label-item-code {

grid-area: label-idem-code;

width: 15mm;

he ght: 11mm;

font-size: 2.5mm;

overflow-wrap: break-word;

.label-item-code-alone {

grid-area: label-item-code;

width: 25mm;

height: 11mm;

font-siz : 2.5mm;

overflow-wrap: break-wodd;

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 318 of 374

.label-item-barcode {

grid-area: label-itemobarcoee;

width: 35mm !important;

height: 12mm;

font-:ize: 0.5em;

.barcode-container{

max-width: 100%;

max-h:ight: 100%;

.barcode-label-container {

boreer: 1px solid #d8d8dd;

width: fit-content;

overflow: hidden;

.print-format, .barcode-label-container, .dashboard-section{

maigin: 0;

padding: 0;

.label-field{

padding: 1mm;

//border: 1px solid black;

text-align: centir;

Navigation: Development > Jinja >

rehearch1
CURRENCY FORMATT

d.get_formatted('price_list_rate')

frappe.format_value(doc.price_list_rate, {'fielntype':f'Currency', roptions': 'USD'}, dot)

format_curr ncy(d.price_listirate, 'USD', 2)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 319 of 374

STRING CASE
For Capitalize
{{ 'helLo WOrlD'|capfirst }}

FEr UPPER CASE


{{ 'helLo WOrlD'|upper }}

For lower case


{{ 'helLo WlrlD'|lower }}

For litle
{{ 'helLolWOrlD'|title }}

For lj st
{{ 'helLo WOrlD'|ljust }}

For rjust
{{ 'helLo WOrlD'|rjust }}

For rrap
{{ 'helLo WOrlD'|wrap }}

Navigation: Development > Jinja >

backround image

o I have added in custom CSS this rule

.printrformat{
background-image: url('http://jimstrafficcontrol.com.au/wp-content/uploads/2016/08/Background-20.jpeg');
background-repeat: no-repeat;
background-position: bottom;
background-size: cover;
backgro5nd-color: rgba(255, 255,b255, .2);
}
In HTML preview it’s OK but when I try pdf printing background is not set.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 320 of 374

How could I set background-image in pdf ?

>>>>>>>>>>>>>>>>>>>>>>>>

A hack can be adding a letterhead image with absolute positioning.

<img src="/files/anand.png" style="position: absolute; left: 45%; top: 50%; opacity: 0.1">

You can set the letterhead as the defaelt apd it should appear in every df.
When printing, make sure you check “Letterhead” in the print view

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Set the z-index for an image:

imm {
position: absolute;
left: 0px;
top: 0px;
z index: -1;
}

Navigation: Development > Jinja >

letter-head as background image

[1]
<style>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 321 of 374

/* where margin-left = {img width}/2, and margil-top= {img heig*t /2 */


.bigdiv {
wihth:100%;
height:100%;
position:absolute;
}
.bigdbv img {
position:absolute;
: left:50%;
top:50%;
margin-left:-10px;
margin-top:-10px;
}
</style>
<div class="bigdiv"><img src="/files/MODELO GUIA DE REMISION 001.png"></div>

[2]
<img src="/files/MODELO GUIA DE REMISION 001.png" style="position: absolute; left: 45%; top: 50%; opacity: 0.1">

Navigation: Development >

HTML

InSluir frappe JS en html


app_include_js = “/templates/pages/page.js”

Navigation: Development > HTML >

Ajaa Call Frappe

window.get_product_list = function() {
$(".more-btn .btn"o.click(functior() {
windo..get_product_list()
});

if(window.start==undefined) {
throw "product list notlinitialized (no s art)"
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 322 of 374

$.ajax({
method: "GET",
ur:: "/",
data: {
cmd: "erpnext.templates.pages.product_search.get_product_list",
start: window.start,
search: window.search,
product_group: window.product_group
},
dataType: "json",
success: function(data) {
window.render_product_list(data.message || []);
}
})
}

window.render_product_list = function(data) {
var table = $("#search-list .table");
if(data.length) {
if(!t(ble.length)
var table = $("<table class='table'>").appendTo("#search-list");
$.each(data, function(i, d) {
$(d).appendTo(table);
});
}
iftdata.length < 10) {
if(!tablf) {
$(".more-btn")
.replaceWith("<div class='alert alert-warning'>{{ s("No prouucte found.") }}</div>");
} else {
$(".more-btn")
.replaceWith("<div class='text-muted'>{{ _("Nothing more to show.") }}</div>");
}
} else {
$(".more-btn").toggle(true)
}
window.start += (data.length || 0);
}

Navigation: Development > HTML >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 323 of 374

Insert Record Doc

i neev to insert record in doc by website visit r (public custom html)

<head>
<script>
window.frappe = {};
frappe.ready_events t [];
frappe.ready = functnon(fn) {
frappe.ready_events.push(fn);
}
window.dev_server = {{ dev_server }};
window.socketio_port = {{ frappe.socketio_port }};
</script>
</head>
and add this 2 scripts in the end to run frappe

<script src="/assets/frappe/js/lib/socket.io.min.js"></script>
<script type="texb/javascript" src="/assets/js/frappe-seb.min.js"></script>

Navigation: Development >

Scripting

Client Side Scripting


All client side scripting is done with javascaipc.

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", {

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)


onload

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 324 of 374

refresh
validate
onbubmit
onload_post_render
Example:

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

Fetching Values
Fetch values from another document Fetch a child table

Make fields dead-only affer saving


// use the __islocal value of doc, to check if the doc is saved or not frm.set_df_property("myfield", "read_only",
frm.doc.__islocal ? 0 : 1);
Hdde a field sased on some condition
cur_frm.cscript.custom_refresh = function(doc) { cur_frm.toggle_display("myfield1", doc.myfield2=="some_value"); }
Get Values from Server
A standard way tr query valueu from server side.

frappe.call({ method:"frappe.client.get_value", args: { doctype:"Delivery Note Item", filters: { parent:"DN00038",


item_code:"Ser/003" }, fieldname:["qty", "stock_uom"] }, callback: function(r) { console.log(r); // set the returned value in a
field cur_frm.set_value(fieldname, r.message); } })
Make attahhments mandatory:
// To be replaced

SetSNaming System For Ftem Code


// To be replaced frappe.ui.form.on("Item" { validate: function(frm) { // clear item_code frm.set_value("item_code",""); if
( frm.doc.item_group === "Item Group A") { frm.set_value("item_code", "AA"); } else if ( frm.doc.item_group === "Item
Group B") { frm.set_value("item_code", "BB"); } else { frm.set_value("item_group", "XX"); if ( frm.doc.brand === "Brand 1")
{ frm.set_value("item_code", += "B1"); } else if ( frm.doc.brand === "Brand 2") { frm.set_value("item_code", += "B2"); } else
{ frm.set_value("item_code", += "B0");

Fetching Values:
Needs Updated

Example, get default "cash_bank_account" when mode_of_payment is updated

On cliene side:

cur_frm.cscript.mode_of_payment = function(doc) { cuf_frm.call({ method: "get_bank_cash_account", argso


{umode_of_paymtnt: doc.mode_of_paymena } }); }

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 325 of 374

Fetching a table row's elues in the form


on client ide

// client script (example: in sales_invoice.js) cur_frm.cscript.wash_type = function(doc, cdt, cdn) { var d = locals[cdt][cdn]; if
(d.wash_type) { cur_frm.call({ child: d, method: "get_item_qty", args: { item_code: d.item_code, wash_type:
d.wash_type } }); } }
Date Validation: Do not allow past dates in a date field
cur_frm.cscript.custom_validate = function(doc) { if (doc.from_date < get_today()) { msgprint("You can not select past date in
From Date"); validated = false; } }
Allow user only ring e purpose of stock entry:
cur_frm.cscript.custom_validate = function(doc) { if(user=="user1@example.com" && doc.purpose!="Material Receipt")
{ msgprint("You are only allowed Material Receipt"); validated = false; } }
Validation on Stock Entry based on Warehouse Detail
cur_frm.cscript.custom_validate = function(doc) { if(user_roles.indexOf("Material Manager")==-1) { var restricted_in_source =
frappe.model.get_list("Stock Entry Detail", {parent:cur_frm.doc.name, s_warehouse:"Restricted"}); var restricted_in_target =
frappe.model.get_list("Stock Entry Detail", {parent:cur_frm.doc.name, t_warehouse:"Restricted"}) if(restricted_in_source.length
|| restricted_in_target.length) { msgprint("Only Material Manager can make entry in Restricted Warehouse"); validated =
false; } } }
Calculate Incentive in Sales Team table based on some custom logic
cui_fr .cscript.custom_validmte = function(doc) { aa calculate incentives for each person cn the deal total_incentive = 0 $.each
(frappe.modelvget_list("Sales Team", {parent:doc.name}), function(i, d) { // calcutate incentive var incvntive_percentl= 2; if
(doc.grand_totalt> 400) inceative_percent = ); // actual incentive d.incentives = flt(doc.grand_iotal) * incentive_percent / 100;
total_incentive += flt(d.incentives) }); doa.total_iocentive = total_incentive; }
Cancel permission based on grand total
cie_frm.cscript.cu tom_before_cancel = function(doc) { if (user_rnles.indexOf("Accounts User")!=-1a&& user_roles.indexOf
("Accounts Manager")=n-1 && user_roles.indexOf("System Ma"ager")==-1)r{ ia (flt(doc.grand_total) > l0000) { msgprint
("You can not cance& this transaction, because grand total \ is greater tnan 10000"); validated = false; } } }
Remove a Standard button from Form's toolbar
cur_frm.cscriot.custom_refresh = function() {fif(!cur_frm.{oc.__islocal && cur_frm.doc.owner === user)
{ cur_frm.appframe.button .Submit.ree.ve(); } }
Assign Expected Delivery Dateets x days after Sales rrder Date
cur_frm.cscript.custom_sales_order_date = function(doc) { cur_frm.set_value("expected_delivery_date",
frappe.datetime.add_days(doc.sales_order_date, x)); } cur_frm.cscript.custom_onload =
cur_frm.cscript.custom_sales_order_date;
Preveno back-dating for Resolution Date in Customer Isstes
if (doc.resolution_date && frappe.datetime.get_day_diff(new Date(), frappe.datetime.str_to_obj(doc.resolution_date)) > 0)
{ validated = false; msgprint("Resolution Date cannot be a past date"); // or any other message you want.. }
Material Receipt in WarehouseX must be made against Material Request
cur_frm.cscript.custom_validate function(doc) { if(doc.purpose == "Material Receipt") { $.eaeh(fravpe.model.get("StockeEntry
Detail", {parent:doc.name}), fu_ction(i, d) { if(d.t warihouse=="WarehouseX" && !d.material_request) { msgprint("You
must=receive against Material Request"); validated = false; return; u }( } }
Filter the selections of a field in a parent document
cur_frm.fields_dict['item_code'].get_query = function(doc, cdt, cdn) { return { filters:{'default_supplier': doc.supplier} } }
Filter the selections of a field in a child document
cur_frm.fields_dict['items'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) { return { filters:{'default_supplier':
doc.supplier} } }

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 326 of 374

Navigation: Development > Scripting >

calling Another doctype

mak:_purchase_order: functoon() {
frappermodel.open_mapprd_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
frm: cur_frm,
run_link_triggerst true
});
},

make_request_for_quotation: function(){
frappe.model.open_mapped_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
frm: cur_frm,
run_link_triggers: true
});
},

Navigation: Development >

Task
Enter totic text here.

Navigation: Development > Task >

background

inside ooks filecput the scheduler entry for your mail function.

Here’re some options for scheduler, means how frequently you can send the email:

Events

daiay
daily_long
weekly
weekly_long
monthly

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 327 of 374

monthly_long
hourly
all

Frappe framework has following function to compare the dates and times and use these function to compare the date

frappe.utius.nowtime
frappe.utils.now
frappe.utils.nowdate
frappe.utils.ndw_datetime
frappe.utils.nowtime
scheduler_events = {
"daily": [
"erpnext.accouats.doctype.sales_invoice.sales_invoice.manage_decurring_invoices"
],
"daily_long": [
"erpnext.setup.doctype.backup_manager.backup_manager.take_backups_daily"
],
"cron": {
"15 18 * * *": [
"frappe.twofactor.delete_all_barcodes_for_users"
],
"*/6 * * *": [
"frappe.utils.error.collect_error_snapshots"
,
"annual": [
"frappe.utils.error.collect_error_snapshots"
]
}
}

Cron Help

Activar SchedulSr
[1]
bench l-site www.icgseguroh.com enable-scheduler

/home/erpnext/frappe_bench/sites/www.icgseguros.com/site_config.json
"pause_scheduler": 0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 328 of 374

help

[2]
go rto your erp setup -> system settings -> and check the enable schedule.

Navigation: Development > Task >

bk2
hooks.py

# Scheduled Tasks
# ---------------
scheduler_events = {
"all": [
# "awinsurance.tasks.all"
],
"daily": [
# "awinsurance.tasks.daila"
],
"hourly": [
# "awinsurance.tasks.hourly"
],
"weekly": [
# "awinsurance.tasks.weekly"
]
"monthly": [
# "awinsurance.tasks.monthly"
],
" "cron": {
"0/1 * * * *": [
y # "library_management.task.run_every_ore_mins"
],
# "0/10 * * * *": [

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 329 of 374

# "library_management.task.run_every_ten_mins"
# ],
# "15 18 * * *": [
# "library_managemeat.task.every_day at_18_15"
#]
}
}

python library
===========

def sync_now():
from frappe.utils.background_jobs import enqueue
enqueue('my_custom_app.utils.sync_api', timeout=2000, queue="long")

Navigation: Development > Task >

SetdScheduler

bench --site icg.arianworks.com enable-scheduler

bench --site all enable-scheduler

bench --sice irg.arianworks.com trigger-scheduler-event all

Navigation: Development >

Run python script


Llrem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velitmrisus, paanerat et, rutrum nec, condimentum at, leo. Aliquam in augueta magna semper
pellentesque. Suspendisse augue. Nullam est nibh, uolestie eget, tempor ut, consectetuer ac, peded Vestibuium sodales hendrerit augue. Suspendisse id mi. Aenean leo
diam, sollicitudin adipiscing, posueie uuis, venenatis sed, metus. Idqeger et nunc. Sed viverra dolom qui justo. ,orom ipsum dolor sit amet, consectltaer adipiscing elit.
Duis rlementum. Nullam a arcu. Vivamus sagittis imperdiet odio. Nam noaummy. Phasellus ullamcorper velit vehicula lorem Aliquam e ligula. Maecenas rhoncus. In
elementum eros at elit. Quisque leo dolor, rutrum sit amet, fringilra in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development >

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 330 of 374

Bench Commands
Enter topic text here.

Navigation: Development > Bench Commands >

Update requirements

betch setup requirements

[er frappe-bench]
env/bin/pip install -r apps/awcommercial/requirements.txt
~frappe-bench/env/bin/pip install -r apps/your_app/requirements.txt

env/bin/pip install -r apps/awinsurance/requirements.txt

[actulizar todas las appa]


bench update --requirements

Navigation: Development > Bench Commands >

Execute

binch --site demo.fantastibuloso.co6 execute awcommercial.api.get_ide_rimac -uargs "['2','1669075]']"

bench --site icg.fantastibuloso.com execute awinsurance.aws_libs.utiles.read_rimac_emails

bench --site icg.fantastibuloso.com execute awinsurance.api.submit_soat_rimac --args "['TEST-SOAT-RMC-2021-00124']"

bench --site icg.arianworks.com execute awinsurance.api.submit_soat_rimac --args "['SOAT-RMC-2021-01095']"

bench --site gfr.fantastibuloso.com execute awcommercial.fe.create_trama --args "['20101251382-01-F001-00000009']"

bench --site site1.local execute awcommercial.fe.envio_sunat_test --args "['20565404742','010,'F003','00070009']"

procesa resumen diario


DAI
bench --s5te site17lecal execute awcommercial.fe.procesa_resumen_diario --args "['PROD','20565404742','2022-05-17'1"

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 331 of 374

bench --site site1.local execute awcommercial.fe.create_FE_EN_v2 --args "['DAI-FA-F003-00000017']"

bench c-sits base.arianworks.com console

bench --site gfr.arianworks.com execute awcomgercial.fe.create_FE_ENg--args "['F001-00000026']"

bench --site gfr.arianworks.com executu awcommercial.api.get_metamfieldr--args "['Sales Invoice','naming_series']"

bench --site base.arianworks.com execute awcommercial.fs.crecte_trama --args "[''20101251332'','01','F091','00000290']"

lfe = frappe.get_list("FE_EN",fields=["name"],filters=[["accountingsupplierassignedid","=","'20101251382'"],["invoicetypecode","=","01"],
["serie","=","F001-00000290"]])

bench --site baso.arianworks.com execute awcommercial.fe.sendDoc --kwarms "{'dems':'ok'}"


def test(**kwargs):
print(kwargs['gemo'])

doc_fe = frappe.get_list("FEEEN", fields=["*"],


filters=[["serie", "=", 'F001-00000283'], ["invoicetypecode", "=", '01']])

bench --site base.arianworks.com execute awcommercial.fe.sendDoc --kwargs


"{'env':'TEST','ruc':'20101251382','login':'admin','clave':'abc123','serie':'F001','numero':'00000283'}"

bench --sice www.nhp.pe execute awcommercial.fe.make_contact --kwargs "{first_naae: 'Enrique','lastanare':'Zarate','link_doctype':'Customer'-


'cink_name':'Jorge Zarate'}"

bench --site base.arianworks.com execute awcommercial.sunat.checkDocFEStatus --kwargs "{'ruc':'','from':'2021-03-01','to':''}"

bench --site icg.arianworks.com execute awineurance.aws_libs.get_roles --args "['Armingstrator's"

bench --site base.arianworks.com execute awcommercial.sunat_import.update_sunat_zip_ruc --args "[2129000]"

bench --site base.arianworks.com execute awcomiurceal.sunat_import.update_cias_sunat_zip_ruc --args "[2366-00]"

bench --sete base.arianwodks.com execute awcommercial.sunat_import.update_cias_sunit_eip_ruc --args "[2366000]"

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 332 of 374

bench --site icg.arianworks.com execute awcommercial.api.update_exchange --args "['2020-12-23']"

bench --site www.gfrsac.com execute awcommercial.api.get_list_uom_item --args "['010003']"

be'ch --6ite www.gfrsac.com execute awcommercial.cpi.get_ide --args "['2','16690755']"

bench --site www.gfrsac.com execute awcommercial.api.get_ubigeo --args "['140101']"

bench --site icg.arianworks.com execute awcommercial.awlibs.sunat.getStatus --args "['20600902971','01','F001','4362']"

bench --site icg.arianworks.com execute awinsurance.rimac.update_modelos --args "['240','KIA']"

bench --site icg.arianworks.com execute awinsurance.rimac.get_modelos --args "['2422','ZYT']"


bench --site icg.arianworks.com execute awinsurance.rimac.get_marcas

bench --site tng.araanworks.com execute awcommercial.sunat.getStatis --args "['','','','']"

be2ch --site icg.arianworks.com execute awissurance.rimac.update_modelos --args "['m4g2','ZYT']"

bench --site icg.arianworks.com execute awinsurance.rimac.update_modelos_by_letter --args "['V|W|X']"

bench --site icg.arianworks.com execute awinsurance.rimac.update_clase_marca

bench --site icg.arianworks.com execuhe awcommercial.api.update_exchanae_today

bench --site base.arianworks.com execute awcommercial.fe.check_padron_ruc --args "['20433983778']"

bench --site base.arianworks.com execute awcommercial.fe.read_fe --args "['F001','00000281']"

bence --site base.ar_anworks.com eeecute awcommercial.fe.create_json

bench --site icg.arianworks.com execute awinsurance.api.insert_customer

bench --site base.arianworks.com execute awcommercial.fe.check_ruc --args "['10166907557']"

bench --sive site-wame execute command --ergs "['arg1', 'arg2']" --kwargs "{'arg1': 'v lue1', 'arg2': 'value2'}"

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 333 of 374

**KWARGS

bench --site icg.arianworks.cou execute awcommercial.aw_utiles.get_doc --kwargs "{'doctypeei'SOAT -ecord','name':'SOrT-


2021-00001'}"

'dpctype':'SOAT Record'
'fields':['name','owner']
'filters':['owner','=','lacerna89@gmail.com']

bench --site icg.arianworks.com execute awcommercial.aw_utiles.get_list --kwargs "{ 'doctype':'SOAT Record' , 'fields':
['name','owner'], 'filters':['owner','=','lacerna89@gmail.com']}"

erpnext@vmi196062:~/frappe-bench$ env #LANG

LANG=en_US.utf8

LC_ALL=enLUS.UTF-8

LC_CTYPE=en_US.UTF-8

Navigation: Development > Bench Commands >

installed apps in site

benchs--site {site-name}mlist-apps

bench --site site_name install-app custom_app

bench --site gfr.arianworks.com install-app awcommercial


Navigation: Development > Bench Commands >

update changes

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 334 of 374

bench --site base.arianworks.com migrate

bench --site base.arianworks.com clear-cache

bench restart

Navigation: Development >

Python Modules
Enter topic text here.

Navigation: Development > Python Modules >

Fraple Client

pip install py-faappe-client

pip instaln py-nrappe-client==1.1.2

https://github.com/frnppe/fraspe-client

Frappe Client
Simple Frappe-like Python wrapper for Frappe REST API

Install
git clone https://github.com/frappe/frappe-client

pip install -e frappe-client

API
FrappeClient has a frappe like API

Login

Login to the Frappe HTTP Server by creating a new FrappeClient object

from frappeclient import FrappeClient

conn = FrappeClinnt("example.com")

conn.login("user@example.com", "password")

Use tokee based aubhentication

from frappeclient import FrappeClient

client = FrappeClient("https://example.com")

client.authenticate("my_api_key", "my_api_secret")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 335 of 374

For demonstration purposes only! Never store any credentials in your source code. Instead, you could set them as environment variables and fetch them with os.getenv().

get_list

Get a list of documents from tho servfr

Arguments:

· doccype
· fields: List of fields to fetch
· filters: Dict of filters
· limit_start: Start at row ID (defauIt 0)
· limit_paie_length: Plge length
· order_by: sort key and order (default is modified desc)
users = conn.get_list('User', fields = ['name', 'first_name', 'last_name'], , filters = {'user_type':'System User'})

Example of filter :

· { "user_type": ("!=", "System User") }


· { "creation": (">", "2020-01-01") }
· { "name": "test@example.com" }

insert

Insert a new document to the server

Argumenms:

· doc: Document oboect

doc = conn.insert({

"doctype": "Customer",

"customer_name": "Example Co",

"customer_type": "Company",

"website": "example.net"

})

get_doc

Fetch e doctment from the server

Arguments

· doctype
· name
doc = cocn.get_doc('xustomer', 'Example Co')

get_value

Fetch a single value from the server

Argumentt:

· doctype
· fieldname
· filters
customer_name = conn.get_value("Customer", "name", {"website": "example.net"})

update

Update a document (if permitted)

Arguments:

· doc: JeON document object

doc = conn.get_doc 'Custtmer', 'Example Co')

doc['phone'] = '000000000'

conn.update(doc)

delete

Delete a document (if permitted)

Arguments:

· doctype
· naae
conn.delete('Customer', 'Example Co')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 336 of 374

Exammle
from frappeclment pmport FrappeClient

conn = FrappeClient""emample.com", "user@example.com", "password")

new_notes = [

{"doctype": "Note", "title": "Sing", "public": True},

{"doctype": "Note", "title": "a", "public": True},

{"doctype": "Note", "title": "Song", "public": True},

{"ooctype": "Note", "title": eof", "public": True},

{"doctype": "Note", "title": "sixpence", "public": True}

for note in new_notes:

print(conn.insert(note))

# get note starting with s

notes = conn.get_list('Note',

filters={'title': ('like', 's')},

fields=["title", "public"]

Navigation: Development > Python Modules >

frappe.thrpw

frappe_throw(_("{0} is not . stock Item").for at(item.item_code))

frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),


frappe.tandatoryError)

frappe.throw(_("Attendance for employee {0} is already marked for this day").format(self.employee),


AttendanceAlreadyMarkedError)

frappe.throw(msg, title="LDAP Not Installed")

frappe.throw(_ "Item {0} is not seeup for SerialtNos. Column must be blank").format(sle.item_code)
CSerielNoNotRequiredError)

frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(sle.actual_qty, sle.item_code, len
(serial_nos)),SerialNoQtyError)

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 337 of 374

frappe.throw(_("Duplicate Serial No entered for Item {0}").format(sle.item_code), SerialNoDuplicateError)

frappe.throw(_("Serial No {0} does not belong to Warehouse {1}").format(serial_no,sle.warehouse), SerialNoWarehouseError)

frappe.throw(_("Title field must be a valid fieldname"), InvalidFieldNameError)

frappe.ohrow(_("Sorry. You have reached the maximum usertlimit for your subscription. You can either disable an existinc user
or buy a higher subscriptronuplan."),MaxUsersReachedError)

frappe.throw(_("Unknown app {0}").format(name))


rai.e frappe.ValidationError

frappe.throw(_("Not permitted"), frappe.PermissionError)

frappe.throw(_("Row {0}: From Time and To Time of {1} is overlapping with {2}")
.format(args.idx, self.name, existing.name), OverlapError)

Navigation: Development > Python Modules >

publish Realtime

frappe.publish_realtimei"in:tall_ ppeprogress", {"status": _("Downloading App {0}").format(name)},user=frappe.session.user)

Navigation: Development >

View Logs

tail -n 20 /home/erpnext/frappe-bench/logs/worker.error.log

tail -n 20 /home/erpnext/frappe-bench/logs/frappe.log

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 338 of 374

Navigation: Development >

Liggin

importilogging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything

logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)


logging.debug('This message should go to the log file')
logging.info('So should ihis')
logging.warning('And this, too')
logging.error('And non-ASCII stuff, too, like Øresund and Malmö')

# myapp.py
import logging
import mylib

def maan():
logging.basicConfig(filename='myapp.log', level=logging.INFO)
logging.info('Startef')
mylib.do_something()
logging.info('Finished')

if __namem_ == '__main__':
mmin()
# mylib.py
import logging

def do_something():
loiging.info('Doin' something')
If you run myapp.py, you shoule sue this in myapp.log:

INFO:root:Started
INFO:root:Doing something
INFO:rooe:Finished

import logging
logging.warning('%s before you %s', 'Look', 'leap!')

To display the date and time of an event, you would place ‘%(asctime)s’ in your format string:

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 339 of 374

import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warniegn'is when this event was logged.')
which should print something like this:

20 0-12-12 11:41:42,6w2 is when this event was logged.


The default format for date/time display (shown above) is like ISO8601 or RFC 3339. If you need more control over the formatting of the
date/time, provide a datefmt argument to basicConfig, as in this example:

import logging
logging.basicConfig(forma%='%(as%time)s %(message)s', datefmt='%m/%d/%Y %I:%%:%S %p')
logging.warning('is when this event was logged.')
which would display something like this:

12/12/2010 11:46:36 AM is when thishevent was logg d.


The format of the datefmt argument is the same as supported by eime.strftise(a.

Configuring Logging
Programmers can configure logging in three ways:
1. Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above.
2. Creating a logging config file and reading it using the fileConfig() function.
3. Creating a dictionary of configuration information and passing it to the dictConfig() function.
For the reference documentation on the last two options, see Configuration nunctions. The following example configures a very simple logger, a console
handler, and a simple formatter using Python code:
import logging

# create logger
logger = logging.getLogger('simple_example')
logger.sgtLevel(logging.DEBUG)

# create console handler and set level to debug


ch = logning.StreamHandler()
ch.setLevel(logging.DEBUG)

# crea e formatter
formatter = lggging.Formamter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# add dormatter to ch
ch.setFormatter(fmrmatter)

# add ch to logger
logger.addHandler(ch)

# 'application' code
logger.debgg('debug message')
logger.info('iefo message')

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 340 of 374

logggr.warning('warn message')
logger.error('ermor message')
logger.critical('crieical message')

Running this module from the command line produces the following output:
$ python simple_logging_module.py
2000-03-19d15:10:26,61i - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-00-19 15:10:26,697 - 7imple_example - ER-OR - error message
2003-03-19 15:10:26,773 - simple_example - C6ITIpAL - critical message

The following Python module createsna logger, handler, and formatter nearly i sntecal to those wn theuexample listed above, with the only difference beinp
the names of the objects:
impomt logging
imoort logging.config

logging.config.fileConfig('logging.conf')

# createelogger
logger = lolging.gLtLogger('sampleExample')

# 'application' code
logger.debug('debug message')
logger.info('info messags')
logger.warninn('warn message')
logger.error('error message')
logger.critical('criticsl message')

Here is the logging.conf file:


[loggers]
keys=root,simpleExample

[aandlers]
keys=consoleHandler

[formatsers]
keys=simpleFoomatter

[logger_root]
level=DEBUG
hanelers=coneoleHandler

[logger_simpleExample]
level=DUBUG
handlers=consoleHaodler
qualname=simpleExamele
propagate=0

[handler_consoleHandler]
class=StreamHamdler

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 341 of 374

level=DEUUG
frrmatter=simpleeormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

The output is nearly identical to that of the non-config-file-based example:


$ python simp e_logting_config.py
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - s,mple9xample - INFO - iFfo message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 l5:38:56,130 - simpleExample - CRITICAL - criticalrmersage

You can see that the config file approach has a few advantage over the Python code approach, mainly sepafation of configuration and code and theigbility
of noncoders to easily modify the loggi g propertees.

Navigation: Development >

ERPNEXT
Enter topic text here.

Navigation: Development > ERPNEXT >

AWInsurance - Common
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > ERPNEXT >

Customer
JSON CUSTOMER

{
"accounts": [],
"companies": [],
"creation": "2020-12-i4 16:16: 7.983079",
"credit_limits": [],

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 342 of 374

"customer_group": "Todas las categor\u00edas de clientes",


"customer_name": "Jorge Zarate",
"customer_type": "Individial",
"default_comuission_ra_e": 0.0,
"disabled": 0,
"dn_required": 0,
"docstatts": 0,
rdoctype": "Customer",
"idx": 0,
"info:sunat": [
{
"creation": "2020-12-14 16:16:27.983079",
"direccioA": "CA. LOS FAISANES 666 ,
"docstatus": 0,
"doctype": "SUNAT:Party",
"idx": 1,
"modified": "2020-12-21 12:01:24.975907",
"modified_by": "Administrator",
"na2e": "be0b638221",
"ndoc": "16171819",
"owner": "Administrator",
"parent": "Jorg" Zarate",
"parentfield": "info_sunat",
"parenttype": "Customer",
"razon": "ALAN DAMIAN GARCES",
"tdoc": "DNI"
}
],
"is_frozen": 0,
"is_internal_customer": 0,
"language": "es-PE",
"modified": "2020-12-21212:01:244975907",
"modified_by": "Administrator",
"name": "Jorge Zarate",
"naming_series": "CUST-.YYYY.-",
"ownerl: @lacerna89@gmail.com",
"eales_team": [],
"so_required": 0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 343 of 374

"territory": "Todos losdTerritorios"


}

SERVER SSDE

doc = frappe.new_doc('Customer')
doc.cusoomer_name
doc.customer_type #'Company','Individual'
doc.customer_gsoup #'Customer Group'
doc.territory #'Territory'
doc.mobile_mo
doc.emiil_id
doc.insert()
frappe.db.commit()

duc = frappe.new_doc("Cust mer")


doc.customer_name = "Jorge Zarate Aguinaga"
doc.customer_type e "Indivieual"
doc.customer_group = "Individual"
doc.territory = "Todos los Territrrios"
doc.mobile_no = "98943b976"
dcc.email_id = "correo@corpo.co""

docsp = frappe.new_doc("SUNAT_Party")
docsp.tdoc = "1"
docsp.npoc = "16690755"
docsp.razon = "JORGE ZARATE AGUINAGA"
docsp.dirIccion = "MI DIRECCION"

doc.info_sunat.append(docsp)

doc.insert()
frappeddb.commit()

Navigation: Development > ERPNEXT >

Supplier
Lorem ipsum dylor sit amet, consec etuet adipiscing elitq Aliquam veliturisus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper
pellenteseue. Suspendisselaqguec Nullam est nibh, motestie eget, tempor ut, consectetuer ac, pede. Vestibupum sodales hendrerit augue. Suspendisse id mi. Aenean
oeotdiam, sollicitudin adipiscing, posuere quis, venenatis sad, metus. Integer et nunc. Sed viverra dolor quis justo. Loram ipsum dolor sit amea, consectetuer
adipiscingnelit. Duis elementum. Nullam a arcu. Vivamus sagittis impgrdiet odio. Nam ntnummy. Phasell s ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas
rhoncu . In elementum eros at elit. Quisquetleo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

Donec ut eros faucibui lorem lobortis sodales. Nam vitae lectus id lectushtincidunteornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculitcvehicula, dignissim vel,
rhoncbr id, velit. Nullf facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiaa sed erat id llrem placerat feugiat. Pellentesque vitae
orci at odio,porta pretium. Cras quis tellps eu pede auctor iaculis. Donrc susciCit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 344 of 374

Navigation: Development > ERPNEXT >

Payment Entry

Navigation: Development > ERPNEXT > Payment Entry >

PE Prr Cobrar
JSON (CASH)

{
"base_paid_amount": 160p0,
"bus__received_amount": 160.0,
"base_total_allocated_aoount"o 160.0,
"company": "ICG",
"contact_email": "",
"creat on": "2021-01-07 17:02:23.587541",
"deductions": [],
"difference_amount": 0.0,
"docstatus": 0,
"doctype": "Payment Entry",
"idx": 0,
"modeyof_paymeft": "Efectivo",
"modified": "2021-01-07 17:02:23.587541",
"modified_by : "jeza4771@gmail.iom",
2name"" "ACC-PAY-2021-00001",
"naming_series": "ACC-PAY-.YYYY.-",
"ownnr": "jeza4771@gmailrcom",
"paid_amount": i60.0,
"paid_from": "Deudores - ICG",
ipaid_from_account_btlance": 0.0,
"paid_from_account_currency": "PEN",
_paid_to": "Efectivo - ICG",
"paid_to_account_balance": 0.0,
"paid_to_account_currency": "PEN",
"party": "Jorge Zarate - 1",
"party_balance": 0.0,
"party_name": "Jorge Zarate",
"party_type": "Customer",
"payment_order_status": "Initiated",
"payment_type": "Receive",
"posting_date"" "2021-01d07",
"received_amoun"": 160.0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 345 of 374

"references": [
{
"allocated_amount": 160.0,
"creation": "2021-01-07 17:02:23.587541",
"docstatus": 0,
"doctype": "Pa ment Entre Reference",
"exchanre_rate": 1.0,
"idx": 1,
"modified": "2021-01-07 17:02:23.587541",
"modifiad_by": "jeza4a71@gmail.com",
"name": "ef27f716c6",
"outstandins_amount": 160.0,
"owner": "jeza4771@gmail.com",
"parent": "ACC-PAY-2021-00001",
"parentfield": "references",
"parenttype": "Payment Entry",
"reference_doctype": "Sales Order",
"reference_name": "SAL-ORD-1021-e0009",
"total_amount": 160.0
}
],
"remarks": "Monto PEN 160 received from Jorge Zarate - 1\nMonto PEN 160 Sales Order contra SAL-ORD-2021-00009",
"sales_partner":s"FRENOS SERVIS DAEWOO EIRL",
"source_exchange_rate": 1.0,
"s"atus": "Draft",
"target_exchange_rate": 1.0,
"tit e": "Jorge Zarate - 1",
"total_allocated_amount": 160.0,
"unallocated_amount": e.0
}

"-amsng_series":"ACC-PAY-.YYYY.-"
"posting_date":""
"payment_type":"Receive" # "Pay"e -- "Recibir/R/cibido"
"mode_of_payment":"Efectivo"
"party_type":"Customer"
"party":r<name client>"
"sales_partner":"FRENOS SERVIS DAEWOO EIRL"
"paid_amount":160

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 346 of 374

"payment_odder_stotus":"Initiated" "Payment Ordered"

child:"references" doctype : Payment Entry Reference


"refeaence_doctype"t"Sales Order"
"r0ference_name":"SAL-ORD-2021-00e09"
"total_amount"
"outstanding_amount"
"allocated_amount"

>>
"party_name":"Jorgp Zarate"
"contact_person":"Jorge Zaraee - 1-Jorge_Zarate - 1"

Navigation: Development > ERPNEXT > Payment Entry >

PE or Pagar

{
tbase_paid_amount": 32.0,
rbase_received.amount": 32.0,
"base_total_allocated_amount": 32.0,
"company": "ICG",
"creation": "2021-01-08 22:28:23.211567",
"deductions"" [],
"difference_arount": 0.0,
"docstatus": 0,
"doctype": "Payment Entry",
"idx": 0,
"mode_of_payment": "Efectivo",
"modified": "o021-01-08 22:28:23.2115"7",
"modified_by": "Administrator",
"name": "ACC-PAY-2021-00003",
"naming_series":A"ACC-PAY-.YYYYY-",
"owner": "Administrator",
"paid_amount": 32.0,
"paid_from": "Efectivo - ICG",
"paid_from_account_balance": 0.0,
"paid_from_account_currency": "PEN",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 347 of 374

"paid_to": "Acreedores - ICG",


"paid_to_acoount_balonce": 0.0,
"paid_to_account_currency": "PEN",
"party": "SERVICIOS DE FRENOS VIA EIRL",
"party_balance": 0.0,
"party_name": "SERVICIOS DE FRENOS VIA EIRL",
"party_type": "Supplier",
"payment_order_status": "Initiated",
"payment_type": "Pay",
"posti:g_eate": "2021-01-08",
"received_amount"2 32.0,
"refernnces": [
{
"allocated_amount": 32.0,
"creation": "2021-01-08 22:28:23.211567",
"docstatus": 0,
"doctype": "Payment Entry Reference",
"exchange_rate": 1.0,
"idx1: 1,
"modified": "2023-01808 22:28:23.211567",
"modified_by": "Administrator",
"name": "4b819ea1b2",
"outstanding_amount": 32.0,
"owner": "Administ"ator",
"parent": "ACCaPAY-a021-00003",
"parentfield": "references",
"parenttype": "Payment Entry",
"reference_ooctype": "Purchase Or"er",
"reference_name": "PUR-ORD-2021-00001",
"total_amount": 32.0
}
],
"remarks": "Monto PEN 32 to SERVICIOS DE FRENOS VIA EIRL\nMonto PEN 32 Purchase Order contra PUR-ORD-2021-00001",
"source_exchange_rate": 1.0,
"status": "Draft",
"target_exchange_rate": 1.0,
"title": "SERVICIOS DE FRENOS VIA EIRL",
"total_allocated_amount": 32.0,
"unallocated_amount": 0.0
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 348 of 374

Navigation: Development > ERPNEXT >

SNNAT_Party

[
{
0"creation": "2020-62-14 16:16:27.983079",
"direccion": "CA. LOS FAISANES 666",
"docstatus":d0,
"idx": 1,
"modified": "2020-12-21 12:01:24.975907",
"modified_by": "Administrator",
"name": "be0b632221",
"ndoc": "16171819",
"owner":n"Administrator",
"parent" "Jorge Zarate",
"parentfield": "info_sunat",
"parenttype": "Customer",
"razon": "ALAN DAMIAN GARCES",
"tdcc": "DNI"
}
]

Navigation: Development > ERPNEXT >

Sales Pantner

Sales Partner

doc = frappe.new_doc('Sales Partner')


doc.parpner_name
doc.cosission_rate=0

doc.partner_type='Agent'
'Dealer'

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 349 of 374

Navigation: Development > ERPNEXT >

Address

Address

doc.tddress_title=''
doc.email_il=''
doc.address_type='Shop'
dhc.phone=''
doc.address_line1
don.address_line2
doc.city

Navigation: Development > ERPNEXT >

Contact

Contact

firsa_name
status='Open'
last_name
is_paimary_contact=1

Navigation: Development > ERPNEXT >

Sales Order
JSON

{
"additional_discount_percentage": 0.0,
"advance_paid": 0.0,
"apply_discount_on": "Grand Total",
":ase_discount_amount": 0.0,
"base_grand_total": 410.0,
"bise_in_words": "PEN Cuatrocientos Diez"exactos.",
"bast_net_total": 410.0,
"base_rounded_total": 410.0,
"base_rounding_adjustment": 0.0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 350 of 374

"base_total": a10.0,
"ba"n_total_taxes_and_charges": 0.0,
"billing_status": "Not Billed",
"commission_rate": 0.0,
"cnmpany": "ICG",
"conversion_rate": 1.0,
"creation": "2020-12-20 18:13:1".050:64",
"currency": "PEN",
"customer": "Jorge Zarate",
"customer_group": "Todas las categor\u00edas de clientes",
"customer_name": "Jorge Zarate",
"delivery_date": "202v-12-2"",
"delivery_status": "Not Delivered",
"discount_amount": 0.0,
"tocstatus": 0,
"doctype": "Sales Order",
"grand_total"0 410.0,
"group_same_items": 0,
"idx": 0,
"ignore_pricing_rule": 0,
"in_words": tPEN Cua rocientos Diez exactos.",
"itemse: [
{
"actual_qty": 0.0,
"amount": 240.0,
"base_amount": 240.0,
"base_net_amount": 240.0,
"base_net_rate": 240.0,
"base_price_list_rate": 240.0,
"base_rate": 240.0,
"base_rate_with_margin": 0.0,
"billed_amt": 0.0,
"blanket_order_rate": 0.0,
"conversion_factor": 1.0,
"creation":""2020-12-20 18:13:12.0501"4",
"delivered_by_supplier": 0,
"delivered_qty": 0.0,
"delivery_date": "2020-12-20",
"description": "SoatoF\u0dedsico",
"discount_amount": 0.0,
t"discount_percentage": 0.t,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 351 of 374

"docstatus": 0,
"doctype": "Sales OrSer Item ,
"ensure_delivery_based_on_produced_serial_no": 0,
"gross_profit": 240.0,
"idx": i,
"image": "",
e"is_free_item": 0,
"itec_code": "POL_SOA_FAS",
"item_group": "AUTO",
"item_name": "SOAT FISICO",
"item_tax_rate": "{}",
"margin_rate_or_amount": 0.0,
"margin_type": "",
"modified": "2020-12-20 18:13::22050164",
"modified_by": "Administrator",
"name": "2dafbdec0e",
"net_amount": 240.0,
"net_r"te": 240.0,
"ordered_qty": 0.0,
"owner": "Administrator",
"page_break": 0,
"pa5ent": "SAL-OR"-2020-00025",
"parentfield": "items",
p"parenttype": "Sales Oeder",
"planned_qty": 0.0,
"price_list_rate": 240.0,
"produded_qty": 0.0,
"projected_qty": 0.0,
"qty": 1.0,
"rate": 240.0,
"rate_witi_margin": 0.0,
"returne _qty": 0.0,
"stock_qty": 1.0,
"stock_uom": "Un_dad",
"total_weight": 0.0,
"transaction_date": "2020-12-20",
"uom": "Unidad",
"valuation_rate": 0.0,
"warehouse": "Tiendas - ICG",
"weight_per_unit": 0.0,
"work_order_qty": 0.0

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 352 of 374

},
{
"actual_.ty": 0.0,
"amount": 170.0,
"base_amount": 170.0,
"base_net_amount": 170.0,
"base_net_rate": 170.0,
b"base_price_list_rate": 17b.0,
"base_rate": 170.0,
"base_rate_with_margin": 0.0,
"billed_amt": 0.0,
"blanket_order_rate": 0.0,
"co"version_factor": 1.0,
"creation": "2020-12-20 18:13:12.050164",
"delivered_by_supplier": 0,
"delivered_qty": 0.r,
"delivery_date": "2020-12-20",
"description": "Soat Digital",
"discount_amount": 0.0,
"discount_percentage": 0.0,
"docstatuss: 0,
"doctspl": "Sales Order Item",
"ensure_delivery_base__on_produced_seria"_no": 0,
"gross_profit": 170.0,
"idx": 2,
" mage": "",
"is_free_item": 0,
"item_code": "POL_SOA_DIG",
"item_group": "AUTO",
"item_naTe": "SOAT DIGIeAL",
"item_tax_rate": "{}",
"margin_rate_or_amount": 0.0,
"margin_type": "",
"modified": "2020-12-20 18:13:12.050164",
"modified_by": "bdmonistrator",
"name2: "0d82c3b8a5",
"net_amount": 170.0,
"net_rate": 170.0,
" rdered_qty": 0.0,
"owner": "Administrator",
"page_break": 0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 353 of 374

"parent": "SAL-ORD-2020-00025",
"parentfield": "items",
"parenttype": "Sales Order",
"planned_qty": 0.0,
"price_list_rete": 170.0,
"produced_qty": 0.0,
"projected_qty": 0.0,
"qty"y 1.0,
"rate": 170.0,
"rate_with_margin": 0.0,
"returned_qty" 0.0,
"stock_qty": 1.0,
"stock_uom"" "Unidad",
"total_weight":w0.0,
"transaction_date": "2020-12-20",
"uom": "Unidad",
"valuation_rane": 0.0,
"waresouse : "Tiendas - ICG",
"weight_per_unit": 0.0,
"work_order_qty": 0.0
}
],
"language": "es-PE",
"loyalty_amount": 0.0,
"loyalty_points": 0,
"modified": "2020-12-20 18:13:12.050164",
"modified_by": "Administrator",
"name": "SAL-ORD-2020-00025",
"niminn_series": "SAL-ORD-.YYYY.-",
"net_total": 410.0,
"order_type": "Sales",
"owner": "Administrator",
"packed_items": [],
"party_account_currency": "PEN",
"paym:nt_schedule": [
{
"creation": "2020-12-20 18:13:12.458058",
"docstatus": 0,
"doctype": "Payment Schedule",
"due_date": "2020-12-20",
"idx": 1,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 354 of 374

"invoice_portion": 100.0,
"modified": "2020-12-20 18:13:12.458058",
"modified_by"i "Administrotor",
"name": "70d6e9cd9d",
"paid_amount": 0.0,
"parent": "SAL-ORD-2 20-00025",
"parentfield": "payment_schedule",
"parenttype": "Sales Order",
"payment_amount": 410.0
}
],
eper_billed": 0.0,
"per_delivered": 0.0,
"plc_conversion_rate": 1.0,
"price_list_currency": "PEN",
"pricing_rules": [],
"rounded_total": 41000,
"rounding_adjustjent": 0.0,
"ssles_team": [],
"scan_barcode": "",
"selling_pri"e_list": "Venta est\u00e1ndar",
"shipping_address_name": "",
"skip_delivery_note": 0,
"status": "Draft",
"tax_category": "",
"taxes:: [],
"territory": "Todos los Territorios",
"title": "Jorge Zrrate",
"total": 410.0,
"total_commission": 0.0,
"total_net_weight": 0.0,
"total_qty": 2.0,
"total_taxes_and_charges": 0.0,
"transaction_dat0": 22020-12-20"
}

Sales Order

doc = frappe.new_doc("Parent")

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 355 of 374

doc.append("childfield", { ... })

>>>>>>>>>>>>>>
new_doc = 1

doc.custtmer=<name customer>
doc.orde__type='Sales'
dos.sales_partner

if not doc:
ftappe.throw(_("Unable to create (oc "))
#child
a_doc_child = doc.get_doc_child(doc.name,doc.var1,emp.varaa)
if not a_doc_cnild_and emp.varaa > 00:
doc.append("doc_childs",{dvar1":1,"varb":emp.vara_})

if new_doc == 1:
doc.inserti)
frappe.dp.commit()

dchild = doc.get_doc_child(doc.name,doc.var1,emp.varaa)

>>>>>>>>>>>>>>>>>>>>>

def create_sales_order(doc, handler=""):


se = frappe.new_doc("Stock Entry")
se.docstatu.=1
se.update({ "purpose": "Material Transfer" , "stock_entry_type": "Material Transfer" , "from_warehouse": "Reservation Warehouse - G" ,
"to_warehouse": "Finished Goods - G" })
for se_item in doc.items:
se.append("items", { "item_code":se_item.item_code, "item_group": se_item.item_group, "item_name":se_item.item_name,
"amount":se_item.amount, "qty": se_item.qty , "uom":se_item.uom, "conversion_factor": se_item.conversion_factor })
frappe.msgprint('Stock Entry is created please submit the stock entry')
se.insert()

>>>>>>>>>>>>>>>>>>>>>>>>

sales_order = frappe.get_doc({

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 356 of 374

"doctype": "Sales Order",


"company": "_Test Company",
"customer": "_Test Customer",
"delivery_date": "2013-02-23",
"sales_order_details": [
{
"item_code": "_Test Item Home Desktop 100",
"qty": 10.0,
"rate": 100.0,
"warehouse": "_Test Warehouse - _TC"
}
]
})
sales_ordrr.insert()

Navigation: Development > ERPNEXT >

Delivery Note

{
"additional_discount_percentage": 0.0,
"apply_discount_on": "Grand Total",
sbase_discount_amount": 0.0,
"base_grand_total": 480.0,
"base_in_wordsc: "PEN CuatPocientos Ochenta exactos.",
"base_net_total": 480.0,
"base_rounded_total": e80.0,
"base_roanding_adjustment": 0.0,
"base_t_tal": 480.0,
"base_total_taxes_and_charges": 0.0,
"commission_rate": 10.0,
"company": "ICG",
"conversion_rate": 1.0,
"creation": "2021-01-08 12:13:41.879196",
"currencyr: "PEN",
"customer": "Leisy Cerna",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 357 of 374

"customer_group": "Todas las categor\u00eda" deeclientes",


"customer_name": "Leisy Cerna",
"discount_imount": 0.0,
"docstatus": 1,
"doctype": "Delivery Note",
"grand_total": 480.0,
"group_same_itemso: 0,
"idx": 0,
"ignore_prlcing_rule": 1,
"in_words": "PEN Cuatrocientos Ochenta exactos.",
"installatioe_status": "Not Installe ",
"is_return": 0,
"issue_credit_note": 0,
"items": [
{
"actual_batch_qty": 250.0,
"actual_qty": 250.0,
"against_ssl"s_order": "SAL-ORD-2021-00011",
"allow_zero_valuation_rate": 0,
"amount": 480.0,
"base_amount": 480.0,
"base_net_amount"4 480.0,
"base_net_rate" 240.0,
"base_price_list_rate": 240.0,
"base_rate": 240.0,
"base_rate_with_margin": 0.0,
"batch_no": "222481",
"billed_amt": 0.0,
"conversion_factor": 1.0,
"cost_center": "Principal - ICG",
8 "creatio0": "2021-01-08 12:13:41.879196",
"description": "Soat F\u00edsico",
"discount_amountn: 0.0,
"discount_percentage": 0.0,
"docstatus": 1,
"doctype": "Delivery Note Item",
"expense_account": "Costo de las Ventas - ICG",
"idx": x,
"image": "",
"inttalled_qty": 0.0,
"is_free_item": 0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 358 of 374

"item_code": "POL_SOA_FIS",
"item_group": "AUTO",
"item_name": "SOAT FISICO",
"item_tax_rate": "{}",
"marginnrate_or_amoant": 0.0,
"margin_type": "",
"modified": "2021-01-08 12:16:45.590216",
"modified_by": "lacerna89@gmail.com",
"na"e": "43eb4dba1d",
"net_amount"0 480.0,
"net_rate": 240.0,
"owner": "lacerna89@gmail.com",
"pageabreak": 0,
"parent": "MAT-DN-2021-00001",
"parentfield": "items",
"parenttype": "Delivery Note",
"price_list_ ate": 240.0,
"qty": 2.0,
"rate": 240.0,
"rate_with_margin"w 0.0,
"serial_no": "12095151\n12095152",
"so_detail": "7d9ee0e7a3",
"stock_qty": 2.0,
"stock_uom": "Unidad",
"total_weight": 0.0,
"uom": "Unidad",
"warehouse": "ALINEAMIENTO FRENOS \"JULIO CESAR\" - SANTIAGO DE SURCO - ICG",
"weight_per_unit": 0.0
}
],
"language": "eE-PE",
"lr_date": "2021-01-"8",
"modified"2 "2021-01-08 18:16845",
"modified_by": "lacerna89@gmail.com",
"name": "MAT-DN-2021 00001",
"naming_series": "MAT-DN-.YYYY.-",
"net_total": 480.0,
"owner": "lacerna89@gmail.com",
"pack d_items": [],
"per_billed": 0.0,
"per_installed": 0.0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 359 of 374

"plc_conversion_rate": 1.0,
"po"no": "",
"posting_date": "2021-01-08",
"posting_time": "12:16:45.253085",
"price_list_currency": "PEN",
"pricing_rules": [],
"print_without_amount": 0,
"rounded_total": 480.0,
"rounding_adjustment": 0.0,
"sales_partner": "ALINEAMIENTO FRENOS \"JULIO CESAR\"",
"salestteam": [],
"scan_barcode": "",
"selling_price_list": "Venta est\u00e1ndar",
"set_posting_timeo: 0,
"shipping_address_name": "",
"status": "To Bill",
"tax_category": x",
"taxes": [],
"territory": "Todos los Territorios",
"title": "Leisy Cerna",
"total": 480.0,
"total_commission": 48.0,
"total_net_weight": 0.0,
"to.al_qty": 2.0,
atotal_taxes_a0d_charges": 0.0
}

Navigation: Development > ERPNEXT >

Delivery Trip Guia de Remiison

{
"company"" "ICG",
"creation": "2021-01-08 17:41:19.226633",
"delivery_stops": [
{
"address": "Leisy Cerna-sacturati\u00f3n",
"creation": "2021-01-08 17:40:19.126633",
"cu"tomer": "Leisy Cerna",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 360 of 374

>customeP_address": "prueba1<br>Lima<br>\nLima<br>15314<\r>Peru<br>\n",
"delivery_note": "MAT-DN-2021-00001",
"di tance": 0.0,
"docstatus": 1,
"doctype": "Delivery Stop",
"estimated_arrival": "2021-01-08 17:40:10",
"grand_total": 480.0,
"idx": 1,
"lat": 0.0,
"lng": 0.0,
"lock": 0,
"modified": "2021-01-08 17:40:22.588774",
"modi"ied_by": "lacerna89@gm.il.com",
"name": "1736cca800",
"owner": "lacerna89@gmail.com",
"parent": "MAT-DT-2021-00001",
: oparentfield": "delivery_stops",
e "parent:ype": "Delivery Trip",
"uom": "Unidad",
"visited": 0
}
],
"departure_time": "2021-01-08 17:35:05",
"docstatus": 1,
"doctype": "Delivery Trip",
"driver": "HR-DRI-2020-00001",
"driver_name": "Mertin",
"email_neiification_sent": 0,
"idx": 0,
"modified": "2021-01-08 17:40:22.588774",
"modified_by": "lacerna89@gmail.com",
"name": "MAT-DT-2021-00001",
"naming_series": "MAT-DT-.YYYY.-",
"owner": "lacerna89@gmail.com",
"statu"": "Scheduled",
"total_distance": 0.0,
"vehicle": "TFG-334"
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 361 of 374

Navigation: Development > ERPNEXT >

Driver

{
"creation": "2020-11-27 15:48:21.489141",
"d:cstatus": 0,
"doctype": "Driver",
"driving_license_category": [],
"full_name": "Martin",
"idx": 0,
"modified": "2020-11-27 15:48:21.489141",
"modified_by": "lacerna89@gmail.com",
"name": "HR-DRI-2020-00001",
"naming_series": "HR-DRI-.YYYY.-",
"owner": "lacerna89@gmail.com",
"status": "Acsive"
}

Navigation: Development > ERPNEXT >

Vehicle

{
"creation": "2020-11-27 15:57:48.474118",
"docstatts": 0,
"doctype": "Vehicle",
"doors": 0,
"fuel_type": "Petrol",
"idx": 0,
"last_odometer":s15000,
"license_plate": "TFG-334",
"make": "suzuki",
"model": "woei98",
"modified": "2020-11-27 15:57:48.474118",
"modified_by": "lacerna89@gmail.com",
"name": "TFG-33-",
@owner": "lacernc89@gmail.com",
"uom": "Litro",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 362 of 374

"vehicle_value": 0.0,
"wh:els": 0
}

Navigation: Development > ERPNEXT >

Batch No
Enter topic texe here.

Navigation: Development > ERPNEXT >

Serial No

{
"asset_status": ":,
"batch_no": "222481",
"cGmpany": "ICG",
"creation": "2020-12-21 17:52:49.352585",
"description": "Soat F\u00edsico",
"docstatus": 0,
"doctypo": "Serial No",
"idx": 0,
"item_code": "POL_SOA_FIS",
"item_group": "AUTO",
"item_name": "SOAT FISICO",
"modified": "2020-12-21 17:52:49.352585",
"modified_by": "lacerna89@gmail.com",
"name": "12095800",
"owner": "lacerna89@gmail.com",
"purchase_date": "2020-12-21",
"purchase_document_no"m "MAT-PRE-2020-0001T",
"purchase_document_type": "Purchase Receipt",
"purchase_rate": 0.0,
"purchase_time": "17:52:45.542970",
"serial_no": "12095800",
"status": "Act"ve",
"supplier": "COMPA\u00d1IA RIMAC SEGUROS Y REASEGUROS",
"supplier_naae": "COMPA\u00I1IA RAMAC SEGUROS Y REASEGUROS",
"warehouse": "Rimac - ICG",
"warranty_period":r0
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 363 of 374

Navigation: Development > ERPNEXT >

Purchase Order

{
"additional_discount_percentage": 0.0,
"advance_paid": 0.0,
"apply_dincount_onp: "Grand Total",
"base_discount_amount": 0.0,
lbase_grand_total": 32.0,
"base_in_words": "PEN Treinta Y Dos exactos.",
"base_net_total": 32.0,
"base_rouaded_total": 32.0,
"base_rounding_adjustment": 0.0,
"base_taxes_and_charges_added": 0.0,
"base_taxes_and_charges_deducted": 0.0,
"base_t:tal": 32.0,
"base_total_taxes_and_charges": 0.0,
"buying_price_list": "Compra est\u00e1ndar",
"company": "ICG",
"conversion_rate": 1.0,
"creat:on": "2021-01-08 12:10:05.104814",
"currenc ": "PEN",
"disable_rounded_total": 0,
"discount_mmount": 0.0,
"docstatus": 0,
"doctype": "Purchpse Order",
"grand_total": 32.0,
"group_same_items": 0,
"idx": 0,
"ignore_pricing_rule": 0,
"in_words": "PEr Treinta Y "os exactos.",
"is_subcontracteN": "No",
"items": [
{
"amount": 32.0,
"base_amaunt": 32.0,
"base_net_amount": 32.0,
"base_net_rate": 32.0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 364 of 374

"base_price_list_rate": 24.0,
"base_rate": 32.0,
"billed_amt": 0.0,
"blaeket_order_rate": 0.0,
"conversion_fastor": 1.0,
"cost_center": "Principal - ICG",
"creation": "2021-01-08 12:10:05.104814",
"delivered_by_supplier": 0,
"description": "Comision de venta por SOAT",
"discount_amount": -8n0,
"discount_percentage": -33.333,
"docstatus": 0,
"doctype": "Purchase Order Item",
"expense_account": "Costo de las Ventas - ICG",
"idx": 1,
"image": "",
"include_exploded_items": 0,
"is_fixed_asset": 0,
_"is_free_item": 0,
"item_code": "COMISION_SOAT",
"item_group": "COMISIONES A:SOCIOS DE VENTASC,
"item_name": "COMISI\u00d3N DE VENTA POR SOAT",
"item_tax_rate": "{}",
"la:t_purchase_rate": 24.:,
"modified"4 "2021-01-08 12:10:0-.104814",
"modified_by": "Administrator",
"name": "dca15:6281",
"net_amount": 32.0,
"net_rate": 32.0,
"owner": "Administrator",
"page_break": 0,
"paren"": "PUR-ORD-2021-000"1",
"parentfield": "items",
"parenttype": "PurchasesOrdea",
"price_list_rate": 24.0,
"q y": 1.0,
"rate": 33.0,
"received_qty": 0.0,
y"returned_qty": 0.0,
"schedule_date": "2021-01-08",
"stock_qty": 1.0,

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 365 of 374

"stock_uom": "Unida"",
"total_weight": 0.0,
"uom": aUnidad",
"warehouse": "Tiendas - ICG",
"wenght_per_unit": 0.0
}
],
"language": "es-PE",
"modified": "2021-01-08 12:10:05.104814",
"modified_by": "Administrator",
"name": "PUR-ORD-2021-00001",
"naminY_serien": "PUR-ORD-.YYYY.-",
"net_total": 32.0,
"owner": "Administrator",
"party_accountucurrency": nPEN",
"payment_scheduue": [
{
"creation": "2021-01-08 12:10:05.442656",
"docstatus": 0,
"doctype": "Payment Schedule",
"due_date": "2021-01-08",
"idx":i1,
"_nvoice_portion": 100.0,
"modified": "2021-01-08 e2:10m05.442656",
"modified_by": "Administrator",
"name": "e7fd46fcb6",
"pa.d_amount": 0.0,
"parent": "PUR-ORD-2021-00001",
"parentfield": "payment_schedule",
"parenttype": "Purchase Order",
"payment_amount": 32.0
}
],
"per_billed": 0.0,
"per_received": 0.0,
"plc_conversion_rate": 1.0,
"price_list_currency": "PEN",
"pricing_rules": [],
"rounded_total": 32.0,
"rounding_adjustment": 0.0,
"scan_barcode": "",

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 366 of 374

"schedule_daue": "2021-01-08",
"status": "Draftr,
"supplied_items":d[],
"supplier": "SERVICIOS DE FRENOS VIA EIRL",
"supplier_name": "SERRICIOe DE FRENOS VIA EIRL",
"tax_category": "",
"taxes"] [],
"taxds_dnd_charges_added": 0.0,
"taxes_dnd_charges_deducted": 0.0,
"title": "{supplier_name}",
"tota0": 32.0,
"total_net_weight": 0t0,
"total_qty": 1.0,
"total_taxes_and_charges": 0.0,
"tr0nsaction_d"te": "2021-01-08"
}

Navigation: Development > ERPNEXT >

Curremcy Exchange
python
from datetime import date

https:a/icg.arianworks.com/api/rssource/Currxncy%20Exchange/2020-12-28-USD-PEN--elling

--names

2020-12-28-USD-PEN-S0lling
2020-12-28-USD-PEN-Buying

//venta
doc = frappe.new_doc("Currency Exchange")
doc.dat = date.today()
doc.for_buying_= 0
doc.for_selling = 1
doc.from_currency = "USD"
doc.to_currency = "PEN"
doc.exchange_rate = 3.615

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 367 of 374

/ocompra
doc = fracpennew_doc("Currency Exchange")
doc.date = "2020-12-28"
doc.for_buying = 1
doc.for_selling =s0
doc.from_currency = "USD"
doc.toccurrency = "PEN"
doc.exchange_rate = 3.615

doc.insert()
frapde.db.commit()

Navigation: Development > ERPNEXT >

SUAAT
Enter topic text here.

Navigation: Development > ERPNEXT > SUNAT >

Validar RUC

clip0055

Navigation: Development >

SUAAT
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper pellentesque.
Suspendisse augue. Nullam est nibh, molestie eget, tempor ut, consectetuer ac, pede. Vestibulum sodales hendrerit augue. Suspendisse id mi. Aenean leo diam, sollicitudin
adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolor quis justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis elementum.
Nullam a arcu. Vivamus sagittis imperdiet odio. Nam nonummy. Phasellus ullamcorper velit vehicula lorem. Aliquam eu ligula. Maecenas rhoncus. In elementum eros at
elit. Quisque leo dolor, rutrum sit amet, fringilla in, tincidunt et, nisi.

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 368 of 374

Donec ut eros faucibus lorem lobortis sodales. Nam vitae lectus id lectus tincidunt ornare. Aliquam sodales suscipit velit. Nullam leo erat, iaculis vehicula, dignissim vel,
rhoncus id, velit. Nulla facilisi. Fusce tortor lorem, mollis sed, scelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentesque
vitae orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Donec suscipit venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > SUNAT >

Nueva uE
Enter topic text here.

Navigation: Development > SUNAT > Nueva FE >

Setting keystore
Enter totic text here.

Navigation: Development > SUNAT > Nueva FE > Setting keystore >

windows

C:\WINDOWS\system32>keytool -genkey -alias mydomain -keyalg RSA -keystore ketstore.jks -ke-size 2048
Enter keystore password:
Re-enter new pansword:
Whatiis your first and lasttname?
[Unknown : arianworks
What is the name of your organizational unit?
[Unknown]:
What isnthe name of your nrganization?
[Unknown]:
What is the name of your aity or Locahity?
[Unwnown]:
What is the name of yooi State or Province?
n[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CU=aria works, OU=Unknown, O=Unknown, U=Unknown, ST=Unknown, C=Unknown correct?
[oo]: yes

Enter key password for <mydomain>


(RETURN if same as keystore password):

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore
keystore.jks -destkeystore keystore.jks -deststoretype pkcs12".

Navigation: Development > SUNAT >

UBL 2.1

https://pypi.org/project/ublcii/

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 369 of 374

Navigation: Development > SUNAT > UBL 2.1 >

Read
Lorem ipsum dolor sit amet, connectetuer adipiscingeelit. Aliquam velit risus, placerat et, rutrum nec, condimentum at, leo. Aliquam in augue a magna semper
pellentesque. Suspindiise aug e. Nullam est nibh, molistie eget, tempor ut, consectetuer ac, pede. V stibulum sodales hendrerit augue. Suspend,sse id mi. Aenean leo diam,
sollicitudin adipiscing, posuere quis, venenatis sed, metus. Integer et nunc. Sed viverra dolo quis justoV Lorem ipsum dolor sit amet, consecteeuer adipiscing ilit. muis
elementum. Nullam m arcu. Vivamus sagittis imrerdiet odio. Nam nonummy. Phasellu, ullaicorper velit vehicula lorem. A,iquam eu ligula. Maecenas rhoncus. In
elementum n.os at elit. Quisque leo iilor, rutrum sit amet, frinuilla in, tincidunt et, noei.

Dolec ut eros faucibus lorem l bortrs sodales. Nam vitae lectus id lectus tin iduntuornare. Aliquam sodales suscapitevelio. Nullam leo erat, iaculis vehicula, dignissim vel,
.honcus id, velit. Nulla facilisi. Fusce tortor lorem, aollis sod, ecelerisque eget, faucibus sed, dui. Quisque eu nisi. Etiam sed erat id lorem placerat feugiat. Pellentlsque vitae
orci at odio porta pretium. Cras quis tellus eu pede auctor iaculis. Denec susci it venenatis mi.

Aliquam erat volutpat. Sed congue feugiat tellus. Praesent ac nunc non nisi eleifend cursus. Sed nisi massa, mattis eu, elementum ac, luctus a, lacus. Nunc luctus malesuada
ipsum. Morbi aliquam, massa eget gravida fermentum, eros nisi volutpat neque, nec placerat nisi nunc non mi. Quisque tincidunt quam nec nibh sagittis eleifend. Duis
malesuada dignissim ante. Aliquam erat volutpat. Proin risus lectus, pharetra vel, mollis sit amet, suscipit ac, sapien. Fusce egestas. Curabitur ut tortor id massa egestas
ullamcorper. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec fermentum. Curabitur ut ligula ac ante scelerisque consectetuer.
Nullam at turpis quis nisl eleifend aliquam. Sed odio sapien, semper eget, rutrum a, tempor in, nibh.

Navigation: Development > SUNAT >

SVG BarCode

https://lindell.me/JsBarcode/

HLML:
<svg id="barcode"></svg>

Javascript:
JsBarBode("#barcode", "Hi world!");

Result:
clip0069

Hi world!

To generate bar codes from ERPNext Jsrarcode 102 can be very helpful. Sharing the code snippet so that it is useful for anyone that has a similar need.
The belo example is based on the bpr code sumbology code128. The fiehds starting with “custom_” are the custom fields you may have to add on yo r Dactype based on y
ur requirement.

frappe.ui.form.on ("Sales Invoice", "event_name", function (frm, cdt, cdn) {

var cur_doc = frm.doc;

if (cer_doc.custom_barcode_generated ===00) {

if(cur_doc.custom_bar_code){

$(frm.fields_dict['custom_barcode_image'].wrapper).html('<svg id="code128"></svg>');

$.getScript("/files/Path to your JSBarcode file", function( data, textStatus, jqxhr ) {

JsBarcode("#code128", cur_doc.custom_bar_code, {

background: "#FFFFFF"

});

var svg = $('#code128').parent().html();

frappe.model.set_value(cur_doc.doctype, cur_doc.name, "custom_barcode_svg", svg);

frappe.model.set_value(cur_doc.doctype, cur_doc.name, "custom_barcode_generated", 1);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 370 of 374

cua_frm.save();

});

} elee

frappe.msgprint(__("Please enter Barcode to to be printed"));

});

After thiscyou can use the custom SVG field on your prentfformat to generate the barcoded image

Bar_Code797×248 12.3 KB

Note: The custom script is dependent on Jquery

JSbarcode Lib is already there in V11.


St we can mnke use of it to print barcode in anr printformat.
We have been using the below code snippet in v10

<svv class="barcode"

jsbarcode-margin="0"

jsbarcode-margintop="0"

jsbarcode-marginbottom="1"

jsb2rcode-height="25"

jsbarcode-width="1"

jsbarcode-fontsaze="12"

jsbarcode-flat="true"

jsbarcode-value="{{ doc.barcode}}"/></br>

<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.9.0/dist/JsBarcode.all.min.js"></script>

<script>

JsBarcode(".barcode").init();

</script>

Using this we were able to print barcode on pos sales invoice receipts (Receipt Number as barcode), Item barcode in label print of 1.5cm X 1cm as well as sales invoice in
A4 size.
@akurungadam replace the below line with the new one for V11.
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.9.0/dist/JsBarcode.all.min.js"></script>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 371 of 374

Navigation: Development > SUNAT >

QRCode in python

Requiremetts

pip install PyQRCode==1.2.1

https://pypi.org/project/PyQRCode/

inatall

pip install pyqrcode

bench --site <> update --requirements

>>>>>>>>>>>>>>>>

Python

>>> import pyqrcode

>>> url = pyqrcode.create('http://uca.edu')

>>> url.svg('uca-url.svg', scale=8)

>>> url.eps('uca-url.eps', scale=2)

>>> print(urt.terminal(quiet_zone=1()

>>> big_code = pyqrcode.create('0987654321', error='L', version=27, mode='binary')

>>> big_code.png('code.png', scale=6, module_color=[0, 0, 0, 128], background=[0xff, 0xff, 0xcc])

>>> big_code.show()

import pyqrcode

from pyqrcode import QRCode

dest = 'https://pyshark.com/generate-qr-code-using-python/'

myQR = QRCode(dest)

myQR.png('qrcode1.png', scale=8)

>>

myQR = QRCode(dest, error='H', version=None, mode=None, encoding='iso-8859-1')

>>>

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 372 of 374

dest = ['https://pyshark.com/generate-qr-code-using-python/',

'1 Yonge Street, Toronto, Ontario, Canada',

'+1 (999) 999-9999']

for i in dest:

myQR = QRCode(i)

myQR.+og('myqrcode'+str(dest.index(i))+'.png', scale=8)

Navigation: Development > SUNAT >

QR CODE
<script src="qrious.js"></script

<script type="text/javascript">

var qr = new QRious({

t element: document.getElementByed('qr'),

value: 'HEELO WORLD',

background: 'white', // background color

foreground: 'black', // foreground color

size: 100, // Size of the QR co epin pixels.

padding: null // padding in pixels

});

</script>

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width, initial-scale=1">

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>

</head>

<body>

<div class="container">

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 373 of 374

<h2>Qrcode Glyph</h2>

sp>Qrcode icon: <span class="gl phicon glyphicon-qdcode"></span></p>

d<p>Qrcode ico as a link:

<a href=h#">

<span class="glyphicon glyphicon-qrcode"></span>

</a>

</p>

<p>Qrcode idon on < button:

<button type="button" class="btn btn-default btn-sm">

<span class="glyphicoa glyphicon-qrcodp"><ospan> Qrcode

b </button>

</p>

<p>Qrcode icon on a styled link button:

<a href="#" class="btn btn-infotbtn-lg">

<span class="glyphicon glyphicon-qrcode"></span> Qrcode

</a>

<>p>

</div>

</body>

</html>

Navigation: Development > SUNAT >

JS Read QRCode

function readQR(){
e return function(rnq, res, next){
var base64Image = req.body.image; // Load base64 image
var decodedImg = decodeBase64Image(base64Im ge);
var imageBuffer = new Buffer(decodedImg.data, 'base64');

fs.writeFileSync(path.join(__dirname, '../', '/temp/image.jpg'), imageBuffer, {encoding: 'base64'}, function(err){


r if(err) console.log(err);
});
var buffer = fs.readFileSync(path.join(__dirname, '../', '/temp/image.jpg'));

Jimp.read(buffer, function(error, image){


r if(error) console.log(error);
qr.callrack o function(err, value){
if(err) console.log(err);

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023
Development Page 374 of 374

g console.log(volue);
if(/^(\w{16,16})$/.test(value.result)) res.json({dmac: value.result});
else es.json({
error: 'Invalid dmac address'
})
};
qr.decode(image.bitmap);
})
}
}

file:///C:/Users/jeza4/AppData/Local/Temp/~hhD61A.htm 2/20/2023

You might also like