from dateutil.relativedelta import relativedelta from odoo import _, api, fields, models DATE_OPTIONS = [ ("1_weeks", _("1 Week")), ("2_weeks", _("2 Weeks")), ("1_months", _("1 Month")), ("2_months", _("2 Month")), ("1_years", _("1 Year")), ("2_years", _("2 Years")), ("custom", _("Custom")), ] class ProjectSprint(models.Model): _name = "project.sprint" _inherit = ["mail.thread", "mail.activity.mixin"] _description = "Project Sprint" _sql_constraints = [ ( "date_check", "CHECK (date_start <= date_end)", _("Error: End date must be greater than start date!"), ), ] name = fields.Char(required=True, tracking=True) user_ids = fields.Many2many( comodel_name="res.users", string="Members", required=True, domain="[('share', '=', False), ('active', '=', True)]", tracking=True, relation="project_sprint_user_rel", ) description = fields.Text(tracking=True) project_id = fields.Many2one( comodel_name="project.project", string="Project", tracking=True, ) task_ids = fields.One2many( comodel_name="project.task", inverse_name="sprint_id", string="Tasks", domain="[('project_id', '=', project_id)]", ) date_start = fields.Date( string="Start Date", default=fields.Date.today, required=True ) date_option = fields.Selection( selection=DATE_OPTIONS, default=DATE_OPTIONS[0][0], required=True ) date_end = fields.Date( string="End Date", required=True, compute="_compute_date_end", store=True, readonly=False, ) state = fields.Selection( selection=[ ("draft", "Draft"), ("in_progress", "In progress"), ("done", "Done"), ], default="draft", ) tasks_count = fields.Integer(compute="_compute_tasks_count") def _compute_tasks_count(self): for sprint in self: sprint.tasks_count = len(sprint.task_ids) def action_start(self): self.write({"state": "in_progress"}) def action_done(self): self.write({"state": "done"}) self._check_task_state() def action_tasks(self): self.ensure_one() return { "name": _("Tasks"), "type": "ir.actions.act_window", "res_model": "project.task", "view_mode": "tree,form", "domain": [("sprint_id", "=", self.id)], "context": { "default_project_id": self.project_id.id, "default_sprint_id": self.id, }, } @api.model def cron_update_sprint_state(self): date = fields.Date.today() for sprint in self.search([("state", "=", "draft")]): if date >= sprint.date_start: sprint.write({"state": "in_progress"}) for sprint in self.search([("state", "=", "in_progress")]): if date >= sprint.date_end: sprint.write({"state": "done"}) sprint._check_task_state() def _check_task_state(self): self.ensure_one() in_progress_sprints = self.project_id.sprint_ids.filtered( lambda sprint: sprint.state == "in_progress" ) self.task_ids.filtered(lambda task: task.kanban_state != "done").write( { "sprint_id": ( in_progress_sprints[0].id if in_progress_sprints else False ), "user_ids": False, } ) @api.depends("date_start", "date_option") def _compute_date_end(self): for record in self: if record.date_option != "custom": num, interval = record.date_option.split("_") record.date_end = record.date_start + relativedelta( **{interval: int(num)} ) else: record.date_end = record.date_start + relativedelta(days=1)