Merge pull request #17146 from Anurag810/timesheet-report
feat: Timesheet report
This commit is contained in:
commit
79c9d5d24a
123
erpnext/projects/report/billing_summary.py
Normal file
123
erpnext/projects/report/billing_summary.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import time_diff_in_hours
|
||||||
|
|
||||||
|
def get_columns():
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"label": _("Employee ID"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"fieldname": "employee",
|
||||||
|
"options": "Employee",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Employee Name"),
|
||||||
|
"fieldtype": "data",
|
||||||
|
"fieldname": "employee_name",
|
||||||
|
"hidden": 1,
|
||||||
|
"width": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Timesheet"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"fieldname": "timesheet",
|
||||||
|
"options": "Timesheet",
|
||||||
|
"width": 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Total Billable Hours"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"fieldname": "total_billable_hours",
|
||||||
|
"width": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Total Hours"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"fieldname": "total_hours",
|
||||||
|
"width": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Amount"),
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"fieldname": "amount",
|
||||||
|
"width": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = []
|
||||||
|
record = get_records(filters)
|
||||||
|
|
||||||
|
for entries in record:
|
||||||
|
total_hours = 0
|
||||||
|
total_billable_hours = 0
|
||||||
|
total_amount = 0
|
||||||
|
entries_exists = False
|
||||||
|
timesheet_details = get_timesheet_details(filters, entries.name)
|
||||||
|
for activity in timesheet_details:
|
||||||
|
entries_exists = True
|
||||||
|
time_start = activity.from_time
|
||||||
|
time_end = frappe.utils.add_to_date(activity.from_time, hours=activity.hours)
|
||||||
|
from_date = frappe.utils.get_datetime(filters.from_date)
|
||||||
|
to_date = frappe.utils.get_datetime(filters.to_date)
|
||||||
|
|
||||||
|
if time_start <= from_date and time_end <= to_date:
|
||||||
|
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||||
|
time_end, from_date, total_hours, total_billable_hours, total_amount)
|
||||||
|
elif time_start >= from_date and time_end >= to_date:
|
||||||
|
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||||
|
to_date, time_start, total_hours, total_billable_hours, total_amount)
|
||||||
|
elif time_start >= from_date and time_end <= to_date:
|
||||||
|
total_hours, total_billable_hours, total_amount = get_billable_and_total_hours(activity,
|
||||||
|
time_end, time_start, total_hours, total_billable_hours, total_amount)
|
||||||
|
|
||||||
|
row = {
|
||||||
|
"employee": entries.employee,
|
||||||
|
"employee_name": entries.employee_name,
|
||||||
|
"timesheet": entries.name,
|
||||||
|
"total_billable_hours": total_billable_hours,
|
||||||
|
"total_hours": total_hours,
|
||||||
|
"amount": total_amount
|
||||||
|
}
|
||||||
|
|
||||||
|
if entries_exists:
|
||||||
|
data.append(row)
|
||||||
|
entries_exists = False
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_records(filters):
|
||||||
|
record_filters = [
|
||||||
|
["start_date", "<=", filters.to_date],
|
||||||
|
["end_date", ">=", filters.from_date]
|
||||||
|
]
|
||||||
|
|
||||||
|
if "employee" in filters:
|
||||||
|
record_filters.append(["employee", "=", filters.employee])
|
||||||
|
|
||||||
|
return frappe.get_all("Timesheet", filters=record_filters, fields=[" * "] )
|
||||||
|
|
||||||
|
def get_billable_and_total_hours(activity, end, start, total_hours, total_billable_hours, total_amount):
|
||||||
|
total_hours += abs(time_diff_in_hours(end, start))
|
||||||
|
if activity.billable:
|
||||||
|
total_billable_hours += abs(time_diff_in_hours(end, start))
|
||||||
|
total_amount += total_billable_hours * activity.billing_rate
|
||||||
|
return total_hours, total_billable_hours, total_amount
|
||||||
|
|
||||||
|
def get_timesheet_details(filters, parent):
|
||||||
|
timesheet_details_filter = {"parent": parent}
|
||||||
|
|
||||||
|
if "project" in filters:
|
||||||
|
timesheet_details_filter["project"] = filters.project
|
||||||
|
|
||||||
|
return frappe.get_all(
|
||||||
|
"Timesheet Detail",
|
||||||
|
filters = timesheet_details_filter,
|
||||||
|
fields=["*"]
|
||||||
|
)
|
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Employee Billing Summary"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
fieldname: "employee",
|
||||||
|
label: __("Employee"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Employee",
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname:"from_date",
|
||||||
|
label: __("From Date"),
|
||||||
|
fieldtype: "Date",
|
||||||
|
default: frappe.datetime.get_today(),
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname:"to_date",
|
||||||
|
label: __("To Date"),
|
||||||
|
fieldtype: "Date",
|
||||||
|
default: frappe.datetime.add_days(frappe.datetime.get_today(), 30),
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"creation": "2019-03-08 15:08:19.929728",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2019-03-08 15:08:19.929728",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Projects",
|
||||||
|
"name": "Employee Billing Summary",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Timesheet",
|
||||||
|
"report_name": "Employee Billing Summary",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Projects User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "HR User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Manufacturing User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from erpnext.projects.report.billing_summary import get_columns, get_data
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
filters = frappe._dict(filters or {})
|
||||||
|
columns = get_columns()
|
||||||
|
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Project Billing Summary"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
fieldname: "project",
|
||||||
|
label: __("Project"),
|
||||||
|
fieldtype: "Link",
|
||||||
|
options: "Project",
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname:"from_date",
|
||||||
|
label: __("From Date"),
|
||||||
|
fieldtype: "Date",
|
||||||
|
default: frappe.datetime.get_today(),
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldname:"to_date",
|
||||||
|
label: __("To Date"),
|
||||||
|
fieldtype: "Date",
|
||||||
|
default: frappe.datetime.add_days(frappe.datetime.get_today(), 30),
|
||||||
|
reqd: 1
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"creation": "2019-03-11 16:22:39.460524",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2019-03-11 16:22:39.460524",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Projects",
|
||||||
|
"name": "Project Billing Summary",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Timesheet",
|
||||||
|
"report_name": "Project Billing Summary",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "Projects User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "HR User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Manufacturing User"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Employee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Accounts User"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe import _
|
||||||
|
from erpnext.projects.report.billing_summary import get_columns, get_data
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
filters = frappe._dict(filters or {})
|
||||||
|
columns = get_columns()
|
||||||
|
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
Loading…
Reference in New Issue
Block a user