[ADD] project_dashboard_billable_hours display billable hours on project dashboard view
This commit is contained in:
1
project_dashboard_billable_hours/models/__init__.py
Normal file
1
project_dashboard_billable_hours/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import project_project
|
||||
104
project_dashboard_billable_hours/models/project_project.py
Normal file
104
project_dashboard_billable_hours/models/project_project.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = "project.project"
|
||||
|
||||
billable_hours = fields.Float(
|
||||
string="Billable Time",
|
||||
compute="_compute_billable_hours",
|
||||
compute_sudo=True,
|
||||
groups="hr_timesheet.group_hr_timesheet_user",
|
||||
)
|
||||
|
||||
@api.depends('timesheet_ids.unit_amount', 'timesheet_ids.so_line')
|
||||
def _compute_billable_hours(self):
|
||||
if not any(self._ids):
|
||||
for project in self:
|
||||
filtered_timesheets = project.timesheet_ids.filtered(
|
||||
lambda t: t.so_line
|
||||
)
|
||||
project.billable_hours = sum(
|
||||
filtered_timesheets.mapped("unit_amount")
|
||||
)
|
||||
return
|
||||
|
||||
timesheet_read_group = self.env["account.analytic.line"]._read_group(
|
||||
[
|
||||
("project_id", "in", self.ids),
|
||||
("so_line", "!=", False),
|
||||
],
|
||||
["project_id"],
|
||||
["unit_amount:sum"],
|
||||
)
|
||||
|
||||
timesheets_per_project = {
|
||||
project.id: unit_amount for project, unit_amount in timesheet_read_group
|
||||
}
|
||||
for project in self:
|
||||
project.billable_hours = timesheets_per_project.get(project.id, 0.0)
|
||||
|
||||
|
||||
|
||||
|
||||
def action_project_billable_timesheets(self):
|
||||
self.ensure_one()
|
||||
action = self.action_billable_time_button() # sale_timesheet
|
||||
action['domain'] = [('project_id', '=', self.id), ('so_line', '!=', False)]
|
||||
action['display_name'] = self.env._("%(name)s's Billable Timesheets", name=self.name)
|
||||
return action
|
||||
|
||||
|
||||
def _get_stat_buttons(self):
|
||||
buttons = super()._get_stat_buttons()
|
||||
if not (self.allow_billable and self.allow_timesheets) \
|
||||
or not self.env.user.has_group("hr_timesheet.group_hr_timesheet_user"):
|
||||
return buttons
|
||||
|
||||
|
||||
encode_uom = self.env.company.timesheet_encode_uom_id
|
||||
uom_ratio = self.env.ref('uom.product_uom_hour').factor / encode_uom.factor
|
||||
billable = self.billable_hours / uom_ratio
|
||||
effective = self.total_timesheet_time / uom_ratio
|
||||
|
||||
color = ""
|
||||
if billable:
|
||||
number = f"{round(billable)} / {round(effective)} {encode_uom.name}"
|
||||
billable_rate = round(100 * billable / effective)
|
||||
if billable_rate < 50:
|
||||
number = self.env._(
|
||||
"%(billable)s / %(effective)s %(uom_name)s",
|
||||
effective=round(effective),
|
||||
billable=round(billable),
|
||||
uom_name=encode_uom.name,
|
||||
)
|
||||
color = "text-danger"
|
||||
else:
|
||||
number = self.env._(
|
||||
"%(billable)s / %(effective)s %(uom_name)s (%(billable_rate)s%%)",
|
||||
effective=round(effective),
|
||||
billable=round(billable),
|
||||
uom_name=encode_uom.name,
|
||||
billable_rate=billable_rate,
|
||||
)
|
||||
if billable_rate < 80:
|
||||
color = "text-warning"
|
||||
else:
|
||||
color = "text-success"
|
||||
else:
|
||||
number = self.env._(
|
||||
"%(billable)s %(uom_name)s",
|
||||
billable=round(billable),
|
||||
uom_name=encode_uom.name,
|
||||
)
|
||||
|
||||
buttons.append({
|
||||
"icon": f"money {color}",
|
||||
"text": self.env._("Billable Time"),
|
||||
"number": number,
|
||||
"action_type": "object",
|
||||
"action": "action_project_billable_timesheets",
|
||||
"show": True,
|
||||
"sequence": 3,
|
||||
})
|
||||
return buttons
|
||||
Reference in New Issue
Block a user