first push message
This commit is contained in:
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,102 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
class ProjectTask(models.Model):
|
||||
_inherit = 'project.task'
|
||||
|
||||
# 1. Type of KPI
|
||||
type_of_kpi = fields.Selection([
|
||||
('percentage', 'Percentage'),
|
||||
('number', 'Number'),
|
||||
('other', 'Other')
|
||||
], string='KPI Type', default='number')
|
||||
|
||||
# 2. Total Number KPI (The Target)
|
||||
total_number_kpi = fields.Float(string='KPI Target', default=0.0)
|
||||
|
||||
# 3. Number of KPI (The Achieved Result)
|
||||
# This is the main field used for storage
|
||||
number_of_kpi = fields.Float(string='KPI Achieved', default=0.0)
|
||||
|
||||
# 4. Dateline of KPI
|
||||
dateline_of_kpi = fields.Date(string='KPI Deadline')
|
||||
|
||||
# 5. Computed Field: Sum of Sub-tasks KPI
|
||||
# This shows what the total would be based on children
|
||||
kpi_achieved_subtask_sum = fields.Float(
|
||||
string='KPI Sum from Subtasks',
|
||||
compute='_compute_kpi_achieved_subtask_sum',
|
||||
store=True
|
||||
)
|
||||
|
||||
# 6. Computed Field: Achievement Rate
|
||||
kpi_achievement_rate = fields.Float(
|
||||
string='KPI Achievement (%)',
|
||||
compute='_compute_kpi_achievement_rate',
|
||||
store=True
|
||||
)
|
||||
|
||||
@api.depends('child_ids.number_of_kpi')
|
||||
def _compute_kpi_achieved_subtask_sum(self):
|
||||
"""Sums the number_of_kpi from all direct sub-tasks"""
|
||||
for task in self:
|
||||
task.kpi_achieved_subtask_sum = sum(task.child_ids.mapped('number_of_kpi'))
|
||||
|
||||
@api.depends('number_of_kpi', 'total_number_kpi')
|
||||
def _compute_kpi_achievement_rate(self):
|
||||
for task in self:
|
||||
if task.total_number_kpi > 0:
|
||||
task.kpi_achievement_rate = (task.number_of_kpi / task.total_number_kpi) * 100
|
||||
else:
|
||||
task.kpi_achievement_rate = 0.0
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('ks_schedule_mode') == 'auto' and vals.get('ks_constraint_task_type') in ['asap', 'alap']:
|
||||
# Example: Set start date to today if auto mode
|
||||
if not vals.get('date_start'):
|
||||
vals['date_start'] = fields.Datetime.now()
|
||||
|
||||
# Example: Auto-calculate deadline based on constraint
|
||||
if vals.get('ks_constraint_task_type') == 'asap':
|
||||
vals['date_deadline'] = vals.get('date_start') + timedelta(days=7)
|
||||
elif vals.get('ks_constraint_task_type') == 'alap':
|
||||
# ALAP logic here
|
||||
pass
|
||||
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
"""Override write to update parent when child KPI changes"""
|
||||
res = super().write(vals)
|
||||
|
||||
# Check if number_of_kpi was updated in this write operation
|
||||
if 'number_of_kpi' in vals:
|
||||
for task in self:
|
||||
if task.parent_id:
|
||||
# Update the parent's KPI based on all its children
|
||||
task.parent_id._update_kpi_from_children()
|
||||
return res
|
||||
|
||||
def _update_kpi_from_children(self):
|
||||
"""Calculates the sum of children KPI and updates the parent's number_of_kpi"""
|
||||
# Ensure we don't trigger infinite recursion by using a specific context or logic
|
||||
# Here we directly update the field via sudo to bypass some checks if needed,
|
||||
# but standard write is safer.
|
||||
if self.child_ids:
|
||||
total_achieved = sum(self.child_ids.mapped('number_of_kpi'))
|
||||
# Only update if different to avoid unnecessary triggers
|
||||
if self.number_of_kpi != total_achieved:
|
||||
# We use super().write to avoid triggering this same method again recursively
|
||||
# However, since we check 'number_of_kpi' in vals, we need to be careful.
|
||||
# To prevent recursion, we can check if the caller is already updating.
|
||||
# Simplest way in Odoo for this case:
|
||||
self.write({'number_of_kpi': total_achieved})
|
||||
|
||||
# Note: The write above will trigger this method again for the Grandparent.
|
||||
# This is desired behavior (cascade update up the tree).
|
||||
# But we must ensure it doesn't trigger for the children again.
|
||||
# Since we only check 'if task.parent_id', and the parent doesn't have a parent_id relative to children,
|
||||
# it won't loop back down.
|
||||
Reference in New Issue
Block a user