feat: Add report table data generation

This commit is contained in:
Hussain Nagaria 2021-03-30 18:20:22 +05:30
parent 2b85a81a1c
commit 1a0229eb36

View File

@ -2,8 +2,128 @@
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
import frappe
from frappe import _
from frappe.utils import flt, getdate
from six import iteritems
def execute(filters=None):
columns, data = [], []
return columns, data
return EmployeeHoursReport(filters).run()
class EmployeeHoursReport:
'''Employee Hours Utilisation Report Based On Timesheet'''
def __init__(self, filters=None):
self.filters = frappe._dict(filters or {})
self.from_date = getdate(self.filters.from_date)
self.to_date = getdate(self.filters.to_date)
self.validate_dates()
def validate_dates(self):
self.day_span = (self.to_date - self.from_date).days
if self.day_span < 0:
frappe.throw(_('From Date must come before To Date'))
def run(self):
self.generate_columns()
self.generate_data()
return self.columns, self.data
def generate_columns(self):
self.columns = [
{
'label': _('Employee'),
'options': 'Employee',
'fieldname': 'employee',
'fieldtype': 'Link',
'width': 200
},
{
'label': _('Total Hours'),
'fieldname': 'total_hours',
'fieldtype': 'Float',
'width': 150
},
{
'label': _('Billed Hours'),
'fieldname': 'billed_hours',
'fieldtype': 'Float',
'width': 150
},
{
'label': _('Non-Billed Hours'),
'fieldname': 'non_billed_hours',
'fieldtype': 'Float',
'width': 150
},
{
'label': _('Untracked Hours'),
'fieldname': 'untracked_hours',
'fieldtype': 'Float',
'width': 150
},
{
'label': _('% Utilization'),
'fieldname': 'per_util',
'fieldtype': 'Percentage',
'width': 200
}
]
def generate_data(self):
self.generate_filtered_time_logs()
self.generate_stats_by_employee()
self.calculate_utilisations()
self.data = []
for emp, data in iteritems(self.stats_by_employee):
row = frappe._dict()
row['employee'] = emp
row.update(data)
self.data.append(row)
def generate_filtered_time_logs(self):
additional_filters = ''
if self.filters.employee:
additional_filters += f'AND tt.employee = {self.filters.employee}'
if self.filters.project:
additional_filters += f'AND ttd.project = {self.filters.project}'
self.filtered_time_logs = frappe.db.sql('''
SELECT tt.employee AS employee, ttd.hours AS hours, ttd.billable AS billable, ttd.project AS project
FROM `tabTimesheet Detail` AS ttd
JOIN `tabTimesheet` AS tt
ON ttd.parent = tt.name
WHERE tt.start_date BETWEEN '{0}' AND '{1}'
AND tt.end_date BETWEEN '{0}' AND '{1}'
{2};
'''.format(self.filters.from_date, self.filters.to_date, additional_filters))
def generate_stats_by_employee(self):
self.stats_by_employee = frappe._dict()
for emp, hours, billable, project in self.filtered_time_logs:
self.stats_by_employee.setdefault(
emp, frappe._dict()
).setdefault('billed_hours', 0.0)
self.stats_by_employee[emp].setdefault('non_billed_hours', 0.0)
if billable:
self.stats_by_employee[emp]['billed_hours'] += flt(hours, 2)
else:
self.stats_by_employee[emp]['non_billed_hours'] += flt(hours, 2)
def calculate_utilisations(self):
# (9.0) Will be fetched from HR settings
TOTAL_HOURS = flt(9.0 * self.day_span, 2)
for emp, data in iteritems(self.stats_by_employee):
data['total_hours'] = TOTAL_HOURS
data['untracked_hours'] = flt(TOTAL_HOURS - data['billed_hours'] - data['non_billed_hours'], 2)
data['per_util'] = flt(((data['billed_hours'] + data['non_billed_hours']) / TOTAL_HOURS) * 100, 2)