# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import _, api, fields, models from odoo.addons.onboarding.models.onboarding_progress import ONBOARDING_PROGRESS_STATES class Onboarding(models.Model): _name = 'onboarding.onboarding' _description = 'Onboarding' _order = 'sequence asc, id desc' name = fields.Char('Name of the onboarding', translate=True) # One word identifier used to define the onboarding panel's route: `/onboarding/{route_name}`. route_name = fields.Char('One word name', required=True) step_ids = fields.Many2many('onboarding.onboarding.step', string='Onboarding steps') text_completed = fields.Char( 'Message at completion', default=_('Nice work! Your configuration is done.'), help='Text shown on onboarding when completed') is_per_company = fields.Boolean( 'Should be done per company?', compute='_compute_is_per_company', readonly=True, store=False, ) panel_close_action_name = fields.Char( 'Closing action', help='Name of the onboarding model action to execute when closing the panel.') current_progress_id = fields.Many2one( 'onboarding.progress', 'Onboarding Progress', compute='_compute_current_progress', help='Onboarding Progress for the current context (company).') current_onboarding_state = fields.Selection( ONBOARDING_PROGRESS_STATES, string='Completion State', compute='_compute_current_progress', readonly=True) is_onboarding_closed = fields.Boolean(string='Was panel closed?', compute='_compute_current_progress') progress_ids = fields.One2many( 'onboarding.progress', 'onboarding_id', string='Onboarding Progress Records', readonly=True, help='All Onboarding Progress Records (across companies).') sequence = fields.Integer(default=10) _sql_constraints = [ ('route_name_uniq', 'UNIQUE (route_name)', 'Onboarding alias must be unique.'), ] @api.depends('progress_ids', 'progress_ids.company_id', 'step_ids', 'step_ids.is_per_company') def _compute_is_per_company(self): # Once an onboarding is made "per-company", there is no drawback to simply still consider # it per-company even when if its last per-company step is unlinked. This allows to avoid # handling the merging of existing progress (step) records. onboardings_with_per_company_steps_or_progress = self.filtered( lambda o: o.progress_ids.company_id or (True in o.step_ids.mapped('is_per_company'))) onboardings_with_per_company_steps_or_progress.is_per_company = True (self - onboardings_with_per_company_steps_or_progress).is_per_company = False @api.depends_context('company') @api.depends('progress_ids', 'progress_ids.is_onboarding_closed', 'progress_ids.onboarding_state', 'progress_ids.company_id') def _compute_current_progress(self): for onboarding in self: current_progress_id = onboarding.progress_ids.filtered( lambda progress: progress.company_id.id in {False, self.env.company.id}) if current_progress_id: onboarding.current_onboarding_state = current_progress_id.onboarding_state onboarding.current_progress_id = current_progress_id onboarding.is_onboarding_closed = current_progress_id.is_onboarding_closed else: onboarding.current_onboarding_state = 'not_done' onboarding.current_progress_id = False onboarding.is_onboarding_closed = False def write(self, vals): """Recompute progress step ids if new steps are added/removed.""" already_linked_steps = self.step_ids res = super().write(vals) if self.step_ids != already_linked_steps: self.progress_ids._recompute_progress_step_ids() return res def action_close(self): """Close the onboarding panel.""" self.current_progress_id.action_close() @api.model def action_close_panel(self, xmlid): """Close the onboarding panel identified by its `xmlid`. If not found, quietly do nothing. """ if onboarding := self.env.ref(xmlid, raise_if_not_found=False): onboarding.action_close() def action_refresh_progress_ids(self): """Re-initialize onboarding progress records (after step is_per_company change). Meant to be called when `is_per_company` of linked steps is modified (or per-company steps are added to an onboarding). """ onboardings_to_refresh_progress = self.filtered( lambda o: o.is_per_company and o.progress_ids and not o.progress_ids.company_id ) onboardings_to_refresh_progress.progress_ids.unlink() onboardings_to_refresh_progress._create_progress() def action_toggle_visibility(self): self.current_progress_id.action_toggle_visibility() def _search_or_create_progress(self): """Create Progress record(s) as necessary for the context.""" onboardings_without_progress = self.filtered(lambda onboarding: not onboarding.current_progress_id) onboardings_without_progress._create_progress() return self.current_progress_id def _create_progress(self): return self.env['onboarding.progress'].create([ { 'company_id': self.env.company.id if onboarding.is_per_company else False, 'onboarding_id': onboarding.id, 'progress_step_ids': onboarding.step_ids.progress_ids.filtered( lambda p: p.company_id.id in [False, self.env.company.id] ), } for onboarding in self ]) def _prepare_rendering_values(self): self.ensure_one() values = { 'close_method': self.panel_close_action_name, 'close_model': 'onboarding.onboarding', 'steps': self.step_ids, 'state': self.current_progress_id._get_and_update_onboarding_state(), 'text_completed': self.text_completed, } return values