my solution
-
create child doctype Project Activity Rate with three fields: Activity Type, Billing Rate, Costing Rate
-
add table type field to project doctype, set option as Project Activity Rate
-
create new app and api.py file, copy the following code to api.py, replace fisher_test with your own app name
import frappe from erpnext.projects.doctype.timesheet.timesheet import get_activity_cost as original_get_activity_cost
@frappe.whitelist() def get_activity_cost(employee=None, activity_type=None, currency=None, project=None):
rate = frappe.db.get_values(“Project Activity Rate”,
{“parent”: project,
“activity_type”: activity_type},
[“costing_rate”, “billing_rate”], as_dict=True) rate = rate and rate[0] or original_get_activity_cost(employee, activity_type, currency)
return rate
- create a js script for Time Sheet doctype, copy the following code, replace fisher_test with your own app name
frappe.ui.form.on(‘Timesheet Detail’, {
activity_type: function(frm, cdt, cdn) {
const child = frappe.get_doc(cdt, cdn);
frappe.call({
method: “fisher_test.api.get_activity_cost”,
args: {
employee: frm.doc.employee,
activity_type: frm.selected_doc.activity_type,
currency: frm.doc.currency,
project:child.project
},
callback: function(r){
if(r.message){
frappe.model.set_value(cdt, cdn, ‘billing_rate’, r.message[‘billing_rate’]);
frappe.model.set_value(cdt, cdn, ‘costing_rate’, r.message[‘costing_rate’]);
let row = frappe.get_doc(cdt, cdn);
let billing_amount = 0.0;
let base_billing_amount = 0.0;
let exchange_rate = flt(frm.doc.exchange_rate);
frappe.model.set_value(cdt, cdn, ‘base_billing_rate’, flt(row.billing_rate) * exchange_rate);
frappe.model.set_value(cdt, cdn, ‘base_costing_rate’, flt(row.costing_rate) * exchange_rate);
if (row.billing_hours && row.is_billable) {
base_billing_amount = flt(row.billing_hours) * flt(row.base_billing_rate);
billing_amount = flt(row.billing_hours) * flt(row.billing_rate);
}
frappe.model.set_value(cdt, cdn, ‘base_billing_amount’, base_billing_amount);
frappe.model.set_value(cdt, cdn, ‘base_costing_amount’, flt(row.base_costing_rate) * flt(row.hours));
frappe.model.set_value(cdt, cdn, ‘billing_amount’, billing_amount);
frappe.model.set_value(cdt, cdn, ‘costing_amount’, flt(row.costing_rate) * flt(row.hours));
}
}
});
}
})
- goto project form view, maintain the activity type billing rate and costing rate for the project
- create new time sheet for the project, select the project at header