brotherton-erpnext/erpnext/projects/report/project_profitability/project_profitability.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

211 lines
5.2 KiB
Python
Raw Normal View History

2021-04-19 11:19:28 +00:00
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
2021-04-20 12:23:41 +00:00
import frappe
from frappe import _
from frappe.utils import flt
2021-04-19 11:19:28 +00:00
2021-04-19 11:19:28 +00:00
def execute(filters=None):
data = get_data(filters)
columns = get_columns()
charts = get_chart_data(data)
return columns, data, None, charts
def get_data(filters):
2021-04-20 12:23:41 +00:00
data = get_rows(filters)
data = calculate_cost_and_profit(data)
return data
def get_rows(filters):
2021-04-19 11:19:28 +00:00
conditions = get_conditions(filters)
2021-04-20 12:23:41 +00:00
standard_working_hours = frappe.db.get_single_value("HR Settings", "standard_working_hours")
if not standard_working_hours:
msg = _("The metrics for this report are calculated based on the Standard Working Hours. Please set {0} in {1}.").format(
frappe.bold("Standard Working Hours"), frappe.utils.get_link_to_form("HR Settings", "HR Settings"))
frappe.msgprint(msg)
return []
sql = """
2021-04-20 12:23:41 +00:00
SELECT
2021-04-19 11:19:28 +00:00
*
2021-04-20 12:23:41 +00:00
FROM
2021-04-19 11:19:28 +00:00
(SELECT
2021-04-20 12:23:41 +00:00
si.customer_name,si.base_grand_total,
si.name as voucher_no,tabTimesheet.employee,
tabTimesheet.title as employee_name,tabTimesheet.parent_project as project,
tabTimesheet.start_date,tabTimesheet.end_date,
tabTimesheet.total_billed_hours,tabTimesheet.name as timesheet,
ss.base_gross_pay,ss.total_working_days,
2021-04-19 11:19:28 +00:00
tabTimesheet.total_billed_hours/(ss.total_working_days * {0}) as utilization
2021-04-20 12:23:41 +00:00
FROM
2021-04-19 11:19:28 +00:00
`tabSalary Slip Timesheet` as sst join `tabTimesheet` on tabTimesheet.name = sst.time_sheet
join `tabSales Invoice Timesheet` as sit on sit.time_sheet = tabTimesheet.name
2021-04-20 12:23:41 +00:00
join `tabSales Invoice` as si on si.name = sit.parent and si.status != "Cancelled"
join `tabSalary Slip` as ss on ss.name = sst.parent and ss.status != "Cancelled" """.format(standard_working_hours)
2021-04-19 11:19:28 +00:00
if conditions:
2021-04-20 12:23:41 +00:00
sql += """
WHERE
{0}) as t""".format(conditions)
return frappe.db.sql(sql,filters, as_dict=True)
def calculate_cost_and_profit(data):
for row in data:
row.fractional_cost = flt(row.base_gross_pay) * flt(row.utilization)
row.profit = flt(row.base_grand_total) - flt(row.base_gross_pay) * flt(row.utilization)
2021-04-19 11:19:28 +00:00
return data
def get_conditions(filters):
conditions = []
2021-04-20 12:23:41 +00:00
if filters.get("company"):
conditions.append("tabTimesheet.company={0}".format(frappe.db.escape(filters.get("company"))))
2021-04-20 12:23:41 +00:00
if filters.get("start_date"):
conditions.append("tabTimesheet.start_date>='{0}'".format(filters.get("start_date")))
if filters.get("end_date"):
conditions.append("tabTimesheet.end_date<='{0}'".format(filters.get("end_date")))
if filters.get("customer_name"):
conditions.append("si.customer_name={0}".format(frappe.db.escape(filters.get("customer_name"))))
2021-04-20 12:23:41 +00:00
if filters.get("employee"):
conditions.append("tabTimesheet.employee={0}".format(frappe.db.escape(filters.get("employee"))))
2021-04-20 12:23:41 +00:00
if filters.get("project"):
conditions.append("tabTimesheet.parent_project={0}".format(frappe.db.escape(filters.get("project"))))
2021-04-20 12:23:41 +00:00
conditions = " and ".join(conditions)
2021-04-19 11:19:28 +00:00
return conditions
def get_chart_data(data):
if not data:
return None
labels = []
utilization = []
for entry in data:
2021-04-20 12:23:41 +00:00
labels.append(entry.get("employee_name") + " - " + str(entry.get("end_date")))
utilization.append(entry.get("utilization"))
2021-04-19 11:19:28 +00:00
charts = {
2021-04-20 12:23:41 +00:00
"data": {
"labels": labels,
"datasets": [
2021-04-19 11:19:28 +00:00
{
2021-04-20 12:23:41 +00:00
"name": "Utilization",
"values": utilization
2021-04-19 11:19:28 +00:00
}
]
},
2021-04-20 12:23:41 +00:00
"type": "bar",
"colors": ["#84BDD5"]
2021-04-19 11:19:28 +00:00
}
return charts
def get_columns():
return [
{
2021-04-20 12:23:41 +00:00
"fieldname": "customer_name",
"label": _("Customer"),
"fieldtype": "Link",
"options": "Customer",
"width": 150
},
{
"fieldname": "employee",
"label": _("Employee"),
"fieldtype": "Link",
"options": "Employee",
"width": 130
},
{
"fieldname": "employee_name",
"label": _("Employee Name"),
"fieldtype": "Data",
"width": 120
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "voucher_no",
"label": _("Sales Invoice"),
"fieldtype": "Link",
"options": "Sales Invoice",
2021-04-25 14:59:14 +00:00
"width": 120
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "timesheet",
"label": _("Timesheet"),
"fieldtype": "Link",
"options": "Timesheet",
2021-04-25 14:59:14 +00:00
"width": 120
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "project",
"label": _("Project"),
"fieldtype": "Link",
"options": "Project",
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "base_grand_total",
"label": _("Bill Amount"),
"fieldtype": "Currency",
"options": "currency",
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "base_gross_pay",
"label": _("Cost"),
"fieldtype": "Currency",
"options": "currency",
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "profit",
"label": _("Profit"),
"fieldtype": "Currency",
"options": "currency",
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "utilization",
"label": _("Utilization"),
"fieldtype": "Percentage",
2021-04-25 14:59:14 +00:00
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "fractional_cost",
"label": _("Fractional Cost"),
"fieldtype": "Int",
2021-04-25 14:59:14 +00:00
"width": 120
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "total_billed_hours",
"label": _("Total Billed Hours"),
"fieldtype": "Int",
2021-04-25 14:59:14 +00:00
"width": 150
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "start_date",
"label": _("Start Date"),
"fieldtype": "Date",
2021-04-25 14:59:14 +00:00
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"fieldname": "end_date",
"label": _("End Date"),
"fieldtype": "Date",
2021-04-25 14:59:14 +00:00
"width": 100
2021-04-19 11:19:28 +00:00
},
{
2021-04-20 12:23:41 +00:00
"label": _("Currency"),
"fieldname": "currency",
"fieldtype": "Link",
"options": "Currency",
2021-04-25 14:59:14 +00:00
"width": 80
2021-04-19 11:19:28 +00:00
}
2021-04-20 12:23:41 +00:00
]