feat: refactor and enhance sales invoice timesheet

(cherry picked from commit 1110f88e5a)

# Conflicts:
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.js
#	erpnext/accounts/doctype/sales_invoice/sales_invoice.py
#	erpnext/accounts/doctype/sales_invoice_timesheet/sales_invoice_timesheet.json
#	erpnext/projects/doctype/timesheet/timesheet.py
This commit is contained in:
barredterra
2021-08-02 23:06:37 +02:00
committed by Mergify
parent fcdf1b4241
commit b2bb4d9020
4 changed files with 170 additions and 27 deletions

View File

@@ -796,7 +796,11 @@ frappe.ui.form.on("Sales Invoice", {
}
},
<<<<<<< HEAD
onload: function (frm) {
=======
onload: function(frm) {
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
frm.redemption_conversion_factor = null;
},
@@ -910,18 +914,34 @@ frappe.ui.form.on("Sales Invoice", {
},
<<<<<<< HEAD
<<<<<<< HEAD
=======
project: function(frm) {
if (frm.doc.project) {
frm.events.add_timesheet_data(frm, {
project: frm.doc.project
});
}
},
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
async add_timesheet_data(frm, kwargs) {
if (kwargs === "Sales Invoice") {
// called via frm.trigger()
kwargs = Object();
}
<<<<<<< HEAD
if (!Object.prototype.hasOwnProperty.call(kwargs, "project") && frm.doc.project) {
=======
if (!kwargs.hasOwnProperty("project") && frm.doc.project) {
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
kwargs.project = frm.doc.project;
}
const timesheets = await frm.events.get_timesheet_data(frm, kwargs);
return frm.events.set_timesheet_data(frm, timesheets);
<<<<<<< HEAD
=======
add_timesheet_row: function(frm, row, exchange_rate) {
frm.add_child('timesheets', {
@@ -931,12 +951,63 @@ frappe.ui.form.on("Sales Invoice", {
'billing_hours': row.billing_hours,
'billing_amount': flt(row.billing_amount) * flt(exchange_rate),
'timesheet_detail': row.name
=======
},
async get_timesheet_data(frm, kwargs) {
return frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_projectwise_timesheet_data",
args: kwargs
}).then(r => {
if (!r.exc && r.message.length > 0) {
return r.message
} else {
return []
}
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
});
frm.refresh_field('timesheets');
},
set_timesheet_data: function(frm, timesheets) {
frm.clear_table("timesheets")
timesheets.forEach(timesheet => {
if (frm.doc.currency != timesheet.currency) {
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
from_currency: timesheet.currency,
to_currency: frm.doc.currency
},
callback: function(r) {
if (r.message) {
exchange_rate = r.message;
frm.events.append_time_log(frm, timesheet, exchange_rate);
}
}
});
} else {
frm.events.append_time_log(frm, timesheet, 1.0);
}
});
},
append_time_log: function(frm, time_log, exchange_rate) {
const row = frm.add_child("timesheets");
row.activity_type = time_log.activity_type;
row.description = time_log.description;
row.time_sheet = time_log.time_sheet;
row.from_time = time_log.from_time;
row.to_time = time_log.to_time;
row.billing_hours = time_log.billing_hours;
row.billing_amount = flt(time_log.billing_amount) * flt(exchange_rate);
row.timesheet_detail = time_log.name;
frm.refresh_field("timesheets");
frm.trigger("calculate_timesheet_totals");
>>>>>>> b57521a337 (feat: add `total_billing_hours` to Sales Invoice)
},
<<<<<<< HEAD
async get_timesheet_data(frm, kwargs) {
return frappe
.call({
@@ -1067,6 +1138,58 @@ frappe.ui.form.on("Sales Invoice", {
},
__("Get Items From")
);
=======
calculate_timesheet_totals: function(frm) {
frm.set_value("total_billing_amount",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_amount"] || 0.0), 0.0));
frm.set_value("total_billing_hours",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_hours"] || 0.0), 0.0));
},
refresh: function(frm) {
if (frm.doc.docstatus===0 && !frm.doc.is_return) {
frm.add_custom_button(__("Fetch Timesheet"), function() {
let d = new frappe.ui.Dialog({
title: __("Fetch Timesheet"),
fields: [
{
"label" : __("From"),
"fieldname": "from_time",
"fieldtype": "Date",
"reqd": 1,
},
{
fieldtype: "Column Break",
fieldname: "col_break_1",
},
{
"label" : __("To"),
"fieldname": "to_time",
"fieldtype": "Date",
"reqd": 1,
},
{
"label" : __("Project"),
"fieldname": "project",
"fieldtype": "Link",
"options": "Project",
"default": frm.doc.project
},
],
primary_action: function() {
const data = d.get_values();
frm.events.add_timesheet_data(frm, {
from_time: data.from_time,
to_time: data.to_time,
project: data.project
});
d.hide();
},
primary_action_label: __("Get Timesheets")
});
d.show();
});
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
}
if (frm.doc.is_debit_note) {
@@ -1111,37 +1234,13 @@ var select_loyalty_program = function (frm, loyalty_programs) {
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.create_dunning",
frm: frm
});
},
calculate_timesheet_totals: function(frm) {
frm.set_value("total_billing_amount",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_amount"] || 0.0), 0.0));
frm.set_value("total_billing_hours",
frm.doc.timesheets.reduce((a, b) => a + (b["billing_hours"] || 0.0), 0.0));
}
});
frappe.ui.form.on("Sales Invoice Timesheet", {
time_sheet: function(frm, cdt, cdn){
var d = locals[cdt][cdn];
if(d.time_sheet) {
frappe.call({
method: "erpnext.projects.doctype.timesheet.timesheet.get_timesheet_data",
args: {
"name": d.time_sheet,
"project": frm.doc.project || null
},
callback: function(r) {
if(r.message) {
frappe.model.set_value(cdt, cdn, "billing_hours", r.message.billing_hours);
frappe.model.set_value(cdt, cdn, "billing_amount", r.message.billing_amount);
frappe.model.set_value(cdt, cdn, "timesheet_detail", r.message.timesheet_detail);
frm.trigger("calculate_timesheet_totals");
}
}
});
}
timesheets_remove(frm, cdt, cdn) {
frm.trigger("calculate_timesheet_totals");
}
});

View File

@@ -1110,6 +1110,7 @@ class SalesInvoice(SellingController):
self.set("timesheets", [])
if self.project:
for data in get_projectwise_timesheet_data(self.project):
<<<<<<< HEAD
self.append(
"timesheets",
{
@@ -1121,6 +1122,16 @@ class SalesInvoice(SellingController):
"description": data.description,
},
)
=======
self.append('timesheets', {
'time_sheet': data.time_sheet,
'billing_hours': data.billing_hours,
'billing_amount': data.billing_amount,
'timesheet_detail': data.name,
'activity_type': data.activity_type,
'description': data.description
})
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
self.calculate_billing_amount_for_timesheet()

View File

@@ -103,6 +103,7 @@
"fieldname": "section_break_11",
"fieldtype": "Section Break",
"label": "Reference"
<<<<<<< HEAD
},
{
"fieldname": "project_name",
@@ -113,11 +114,17 @@
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
=======
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
}
],
"istable": 1,
"links": [],
<<<<<<< HEAD
"modified": "2024-03-27 13:10:36.562795",
=======
"modified": "2021-08-02 23:03:08.084930",
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Timesheet",

View File

@@ -298,8 +298,14 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
if from_time and to_time:
condition += "AND CAST(tsd.from_time as DATE) BETWEEN %(from_time)s AND %(to_time)s"
<<<<<<< HEAD
query = f"""
SELECT
=======
return frappe.db.sql("""
SELECT
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
tsd.name as name,
tsd.parent as time_sheet,
tsd.from_time as from_time,
@@ -308,6 +314,7 @@ def get_projectwise_timesheet_data(project=None, parent=None, from_time=None, to
tsd.billing_amount as billing_amount,
tsd.activity_type as activity_type,
tsd.description as description,
<<<<<<< HEAD
ts.currency as currency,
tsd.project_name as project_name
FROM `tabTimesheet Detail` tsd
@@ -343,6 +350,25 @@ def get_timesheet_detail_rate(timelog, currency):
return timelog_detail.billing_amount * exchange_rate
return timelog_detail.billing_amount
=======
ts.currency as currency
FROM `tabTimesheet Detail` tsd
INNER JOIN `tabTimesheet` ts
ON ts.name = tsd.parent
WHERE tsd.parenttype = 'Timesheet'
AND tsd.docstatus=1 {0}
AND tsd.is_billable = 1
AND tsd.sales_invoice is null
""".format(condition), {
'project': project,
'parent': parent,
'from_time': from_time,
'to_time': to_time
}, as_dict=1)
>>>>>>> 1110f88e5a (feat: refactor and enhance sales invoice timesheet)
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs