mirror of
https://github.com/bringout/oca-ocb-project.git
synced 2026-04-20 21:22:02 +02:00
19.0 vanilla
This commit is contained in:
parent
a2f74aefd8
commit
4a4d12c333
844 changed files with 212348 additions and 270090 deletions
|
|
@ -4,28 +4,35 @@
|
|||
from collections import defaultdict
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools import format_date
|
||||
|
||||
from .project_task import CLOSED_STATES
|
||||
|
||||
|
||||
class ProjectMilestone(models.Model):
|
||||
_name = 'project.milestone'
|
||||
_description = "Project Milestone"
|
||||
_inherit = ['mail.thread']
|
||||
_order = 'deadline, is_reached desc, name'
|
||||
_order = 'sequence, deadline, is_reached desc, name'
|
||||
|
||||
def _get_default_project_id(self):
|
||||
return self.env.context.get('default_project_id') or self.env.context.get('active_id')
|
||||
|
||||
name = fields.Char(required=True)
|
||||
project_id = fields.Many2one('project.project', required=True, default=_get_default_project_id, ondelete='cascade')
|
||||
sequence = fields.Integer('Sequence', default=10)
|
||||
project_id = fields.Many2one('project.project', required=True, default=_get_default_project_id, domain=[('is_template', '=', False)], index=True, ondelete='cascade')
|
||||
deadline = fields.Date(tracking=True, copy=False)
|
||||
is_reached = fields.Boolean(string="Reached", default=False, copy=False)
|
||||
reached_date = fields.Date(compute='_compute_reached_date', store=True)
|
||||
task_ids = fields.One2many('project.task', 'milestone_id', 'Tasks')
|
||||
reached_date = fields.Date(compute='_compute_reached_date', store=True, export_string_translation=False)
|
||||
task_ids = fields.One2many('project.task', 'milestone_id', 'Tasks', export_string_translation=False)
|
||||
project_allow_milestones = fields.Boolean(compute='_compute_project_allow_milestones', search='_search_project_allow_milestones', compute_sudo=True, export_string_translation=False)
|
||||
|
||||
# computed non-stored fields
|
||||
is_deadline_exceeded = fields.Boolean(compute="_compute_is_deadline_exceeded")
|
||||
is_deadline_future = fields.Boolean(compute="_compute_is_deadline_future")
|
||||
task_count = fields.Integer('# of Tasks', compute='_compute_task_count', groups='project.group_project_milestone')
|
||||
can_be_marked_as_done = fields.Boolean(compute='_compute_can_be_marked_as_done', groups='project.group_project_milestone')
|
||||
is_deadline_exceeded = fields.Boolean(compute="_compute_is_deadline_exceeded", export_string_translation=False)
|
||||
is_deadline_future = fields.Boolean(compute="_compute_is_deadline_future", export_string_translation=False)
|
||||
task_count = fields.Integer('# of Tasks', compute='_compute_task_count', groups='project.group_project_milestone', export_string_translation=False)
|
||||
done_task_count = fields.Integer('# of Done Tasks', compute='_compute_task_count', groups='project.group_project_milestone', export_string_translation=False)
|
||||
can_be_marked_as_done = fields.Boolean(compute='_compute_can_be_marked_as_done', export_string_translation=False)
|
||||
|
||||
@api.depends('is_reached')
|
||||
def _compute_reached_date(self):
|
||||
|
|
@ -45,36 +52,51 @@ class ProjectMilestone(models.Model):
|
|||
|
||||
@api.depends('task_ids.milestone_id')
|
||||
def _compute_task_count(self):
|
||||
task_read_group = self.env['project.task']._read_group([('milestone_id', 'in', self.ids), ('allow_milestones', '=', True)], ['milestone_id'], ['milestone_id'])
|
||||
task_count_per_milestone = {res['milestone_id'][0]: res['milestone_id_count'] for res in task_read_group}
|
||||
all_and_done_task_count_per_milestone = {
|
||||
milestone.id: (count, sum(state in CLOSED_STATES for state in state_list))
|
||||
for milestone, count, state_list in self.env['project.task']._read_group(
|
||||
[('milestone_id', 'in', self.ids), ('allow_milestones', '=', True)],
|
||||
['milestone_id'], ['__count', 'state:array_agg'],
|
||||
)
|
||||
}
|
||||
for milestone in self:
|
||||
milestone.task_count = task_count_per_milestone.get(milestone.id, 0)
|
||||
milestone.task_count, milestone.done_task_count = all_and_done_task_count_per_milestone.get(milestone.id, (0, 0))
|
||||
|
||||
def _compute_can_be_marked_as_done(self):
|
||||
if not any(self._ids):
|
||||
for milestone in self:
|
||||
milestone.can_be_marked_as_done = not milestone.is_reached and all(milestone.task_ids.is_closed)
|
||||
milestone.can_be_marked_as_done = not milestone.is_reached and all(milestone.task_ids.mapped(lambda t: t.is_closed))
|
||||
return
|
||||
|
||||
unreached_milestones = self.filtered(lambda milestone: not milestone.is_reached)
|
||||
(self - unreached_milestones).can_be_marked_as_done = False
|
||||
if unreached_milestones:
|
||||
task_read_group = self.env['project.task']._read_group(
|
||||
[('milestone_id', 'in', unreached_milestones.ids)],
|
||||
['milestone_id', 'is_closed', 'task_count:count(id)'],
|
||||
['milestone_id', 'is_closed'],
|
||||
lazy=False,
|
||||
)
|
||||
task_count_per_milestones = defaultdict(lambda: (0, 0))
|
||||
for res in task_read_group:
|
||||
opened_task_count, closed_task_count = task_count_per_milestones[res['milestone_id'][0]]
|
||||
if res['is_closed']:
|
||||
closed_task_count += res['task_count']
|
||||
else:
|
||||
opened_task_count += res['task_count']
|
||||
task_count_per_milestones[res['milestone_id'][0]] = opened_task_count, closed_task_count
|
||||
for milestone in unreached_milestones:
|
||||
opened_task_count, closed_task_count = task_count_per_milestones[milestone.id]
|
||||
milestone.can_be_marked_as_done = closed_task_count > 0 and not opened_task_count
|
||||
task_read_group = self.env['project.task']._read_group(
|
||||
[('milestone_id', 'in', unreached_milestones.ids)],
|
||||
['milestone_id', 'state'],
|
||||
['__count'],
|
||||
)
|
||||
task_count_per_milestones = defaultdict(lambda: (0, 0))
|
||||
for milestone, state, count in task_read_group:
|
||||
opened_task_count, closed_task_count = task_count_per_milestones[milestone.id]
|
||||
if state in CLOSED_STATES:
|
||||
closed_task_count += count
|
||||
else:
|
||||
opened_task_count += count
|
||||
task_count_per_milestones[milestone.id] = opened_task_count, closed_task_count
|
||||
for milestone in unreached_milestones:
|
||||
opened_task_count, closed_task_count = task_count_per_milestones[milestone.id]
|
||||
milestone.can_be_marked_as_done = closed_task_count > 0 and not opened_task_count
|
||||
|
||||
@api.depends('project_id.allow_milestones')
|
||||
def _compute_project_allow_milestones(self):
|
||||
for milestone in self:
|
||||
milestone.project_allow_milestones = milestone.project_id.allow_milestones
|
||||
|
||||
def _search_project_allow_milestones(self, operator, value):
|
||||
query = self.env['project.project'].sudo()._search([
|
||||
('allow_milestones', operator, value),
|
||||
])
|
||||
return [('project_id', 'in', query)]
|
||||
|
||||
def toggle_is_reached(self, is_reached):
|
||||
self.ensure_one()
|
||||
|
|
@ -94,7 +116,7 @@ class ProjectMilestone(models.Model):
|
|||
|
||||
@api.model
|
||||
def _get_fields_to_export(self):
|
||||
return ['id', 'name', 'deadline', 'is_reached', 'reached_date', 'is_deadline_exceeded', 'is_deadline_future', 'can_be_marked_as_done']
|
||||
return ['id', 'name', 'deadline', 'is_reached', 'reached_date', 'is_deadline_exceeded', 'is_deadline_future', 'can_be_marked_as_done', 'sequence']
|
||||
|
||||
def _get_data(self):
|
||||
self.ensure_one()
|
||||
|
|
@ -103,12 +125,19 @@ class ProjectMilestone(models.Model):
|
|||
def _get_data_list(self):
|
||||
return [ms._get_data() for ms in self]
|
||||
|
||||
@api.returns('self', lambda value: value.id)
|
||||
def copy(self, default=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
milestone_copy = super(ProjectMilestone, self).copy(default)
|
||||
if self.project_id.allow_milestones:
|
||||
milestone_mapping = self.env.context.get('milestone_mapping', {})
|
||||
milestone_mapping[self.id] = milestone_copy.id
|
||||
return milestone_copy
|
||||
default = dict(default or {})
|
||||
new_milestones = super().copy(default)
|
||||
milestone_mapping = self.env.context.get('milestone_mapping', {})
|
||||
for old_milestone, new_milestone in zip(self, new_milestones):
|
||||
if old_milestone.project_id.allow_milestones:
|
||||
milestone_mapping[old_milestone.id] = new_milestone.id
|
||||
return new_milestones
|
||||
|
||||
def _compute_display_name(self):
|
||||
super()._compute_display_name()
|
||||
if not self.env.context.get('display_milestone_deadline'):
|
||||
return
|
||||
for milestone in self:
|
||||
if milestone.deadline:
|
||||
milestone.display_name = f'{milestone.display_name} - {format_date(self.env, milestone.deadline)}'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue