detail for each mission in career

This commit is contained in:
Florian du Garage Num 2024-03-08 16:16:56 +01:00
parent 1e8f55fe09
commit 45c1e9613e
9 changed files with 153 additions and 22 deletions

View File

@ -11,7 +11,7 @@ Addons for Odoo 16.
| gn_cc | 16.0.0.0.2 | Configuration for French convention collective, with data for IDCC3442 |
| gn_holidays | 16.0.0.0.1 | French configuration for Publics Holidays and Leave Management |
| gn_contract | 16.0.0.0.1 | Amendements to Hr Contracts |
| gn_career | 16.0.0.0.1 | Fiche de poste et évolution de carrière |
| gn_career | 16.0.0.0.2 | Fiche de poste et évolution de carrière |
## ToDo

View File

@ -12,6 +12,8 @@ Module de gestion des fiches de postes et des évolutions de carrière
- v16.0.0.0.1 (2024/03/02):
- Création du module
- v16.0.0.0.2 (2024/03/08):
- Add detail of Missions for each Career
## Issues

View File

@ -1,6 +1,6 @@
{
"name": "France - Fiche de poste",
"version": "16.0.0.0.1",
"version": "16.0.0.0.2",
"category": "HR",
"summary": "Configuration de la fiche de poste et de son évolution conventionnelle",
"author": "Le Garage Numérique",
@ -14,6 +14,7 @@
],
"data": [
"views/gn_career.xml",
"views/gn_career_detail.xml",
"views/gn_contract.xml",
"data/gn_career_menus.xml",
"security/ir.model.access.csv",

View File

@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api
from odoo.exceptions import ValidationError
import logging
_logger = logging.getLogger(__name__)
@ -11,6 +12,7 @@ class GnCareer(models.Model):
_description = "Analyse du poste"
_order = 'start_date'
name = fields.Char("Nom", compute='_compute_name')
start_date = fields.Date('From', required=True, default=lambda self: fields.Date.today())
contract_id = fields.Many2one('hr.contract', string="Contrat ou Avenant associé")
@ -23,13 +25,46 @@ class GnCareer(models.Model):
('active', 'Active'),
], string="Statut", default='draft')
mission_ids = fields.Many2many('gn_career.mission', string="Missions effectuées")
mission_rel_ids = fields.One2many('gn_career.mission_career_rel', 'career_id', string="Mission Relations")
mission_ids = fields.Many2many('gn_career.mission', 'career_ids', compute='_compute_mission_ids', string="Missions effectuées")
mission_detail_ids = fields.One2many('gn_career.mission.detail', 'career_id', string="Détail de la mission")
class GnCareerMissionCareerRel(models.Model):
_name = 'gn_career.mission_career_rel'
_description = "Répartition des missions au sein d'une analyse de poste"
total_percentage = fields.Float(compute='_compute_total_percentage', string="Total Percentage")
mission_id = fields.Many2one('gn_career.mission', string="Mission")
@api.depends('mission_detail_ids.percentage')
def _compute_total_percentage(self):
for record in self:
record.total_percentage = sum(mission.percentage for mission in record.mission_detail_ids)
@api.constrains('mission_detail_ids', 'total_percentage')
def _check_total_percentage(self):
for record in self:
if record.total_percentage != 100:
raise ValidationError("Le pourcentage total des missions au sein de la fiche de poste doit atteindre 100%. Veuillez ajuster la répartition de la mission.")
@api.depends('mission_detail_ids.mission_id')
def _compute_mission_ids(self):
for record in self:
mission_ids_set = set()
for mission_detail in record.mission_detail_ids:
mission_ids_set.add(mission_detail.mission_id.id)
record.mission_ids = [(6, 0, list(mission_ids_set))]
@api.depends('start_date')
def _compute_name(self):
for record in self:
if record.start_date:
# Use an f-string for formatting
record.name = f"Fiche de poste du {record.start_date}"
else:
# Provide a default or handle the case where start_date isn't set
record.name = "Fiche de poste sans date"
class GnCareerMissionDetail(models.Model):
_name = 'gn_career.mission.detail'
_description = "Détails d'une mission pour une fiche de poste"
name = fields.Char(related='mission_id.name')
career_id = fields.Many2one('gn_career.career', string="Fiche de poste")
percentage = fields.Float("Temps occupé par la mission en %")
mission_id = fields.Many2one('gn_career.mission', string="Mission")
percentage = fields.Integer("Temps occupé par la mission en %", default="100")
task_ids = fields.Many2many('gn_career.task', 'mission_detail', string="Tâches incluses dans la mission")

View File

@ -2,6 +2,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api
import logging
_logger = logging.getLogger(__name__)
class GnCareerContract(models.Model):
_inherit = "hr.contract"
@ -9,9 +12,46 @@ class GnCareerContract(models.Model):
career_ids = fields.One2many("gn_career.career", 'contract_id',
string="Analyses du poste")
active_career_id = fields.Many2one('gn_career.career', string="Fiche de poste en cours", compute='_compute_active_career', store=True)
has_active_career = fields.Integer(compute='_has_active_career')
@api.depends('career_ids')
def _compute_active_career(self):
for record in self:
active_careers = record.career_ids.filtered(lambda c: c.status == 'active').sorted(key=lambda c: c.start_date, reverse=True)
record.active_career_id = active_careers[:1].id if active_careers else False
record.active_career_id = active_careers[0] if active_careers else False
@api.depends('active_career_id')
def _has_active_career(self):
for record in self:
record.has_active_career = True if record.active_career_id else False
#@api.model
def open_associated_careers(self):
_logger.warning("Open Active Career called on records: %s", self)
self.ensure_one() # Ensure that the method is called on a single record
associated_contract_ids = [self.id,]
if self.previous_contract_id:
previous_contract = self.previous_contract_id
while previous_contract:
associated_contract_ids.append(previous_contract.id)
previous_contract = previous_contract.previous_contract_id
action = {
'type': 'ir.actions.act_window',
"views": [[False, "tree"], [False, "form"]],
'res_model': 'gn_career.career',
'target': 'current',
'domain': [('contract_id', 'in', associated_contract_ids)],
}
return action
def open_active_career(self):
action = {
'type': 'ir.actions.act_window',
"views": [[False, "form"]],
'res_model': 'gn_career.career',
'res_id': self.active_career_id.id, # ID of the career to open
'target': 'current',
}
return action

View File

@ -9,8 +9,9 @@ class GnCareerTask(models.Model):
name = fields.Char("Nom de la tâche")
description = fields.Text("Description de la tâche")
mission_ids = fields.Many2many('gn_career.mission', string="Missions impliquant cette tâche")
possible_mission_ids = fields.Many2many('gn_career.mission', string="Missions pouvant inclure cette tâche")
effective_mission_ids = fields.Many2many('gn_career.mission.detail', relation="effective_missions", string="Missions définies impliquant cette tâche")
active_mission_ids = fields.Many2many('gn_career.mission.detail', relation="active_missions", string="Missions actives incluant cette tâche")
class GnCareerMission(models.Model):
_name = 'gn_career.mission'
@ -20,5 +21,5 @@ class GnCareerMission(models.Model):
description = fields.Text("Description de la mission")
task_ids = fields.Many2many('gn_career.task', string="Tâches pouvant être incluses dans la mission")
career_ids = fields.Many2many('gn_career.career', string="Fiches de poste incluant cette mission")
career_mission_ids = fields.One2many('gn_career.mission_career_rel', 'mission_id', string="Répartition des missions au sein du poste")
career_ids = fields.Many2many('gn_career.career', 'mission_ids', string="Fiches de poste incluant cette mission")
career_mission_ids = fields.One2many('gn_career.mission.detail', 'mission_id', string="Répartition des missions au sein du poste")

View File

@ -1,9 +1,9 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_gn_career_career_user,gn_career_career_user,model_gn_career_career,base.group_user,1,0,0,0
access_gn_career_career_admin,gn_career_career_admin,model_gn_career_career,hr_contract.group_hr_contract_manager,1,1,1,1
access_gn_career_mission_career_rel_user,gn_career_mission_career_rel_user,model_gn_career_mission_career_rel,base.group_user,1,0,0,0
access_gn_career_mission_career_rel_admin,gn_career_mission_career_rel_admin,model_gn_career_mission_career_rel,hr_contract.group_hr_contract_manager,1,1,1,1
access_gn_career_task_user,gn_career_task_user,model_gn_career_task,base.group_user,1,0,0,0
access_gn_career_task_admin,gn_career_task_admin,model_gn_career_task,hr_contract.group_hr_contract_manager,1,1,1,1
access_gn_career_mission_user,gn_career_mission_user,model_gn_career_mission,base.group_user,1,0,0,0
access_gn_career_mission_admin,gn_career_mission_admin,model_gn_career_mission,hr_contract.group_hr_contract_manager,1,1,1,1
access_gn_career_mission_detail_user,gn_career_mission_detail_user,model_gn_career_mission_detail,base.group_user,1,0,0,0
access_gn_career_mission_detail_admin,gn_career_mission_detail_admin,model_gn_career_mission_detail,hr_contract.group_hr_contract_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_gn_career_career_user gn_career_career_user model_gn_career_career base.group_user 1 0 0 0
3 access_gn_career_career_admin gn_career_career_admin model_gn_career_career hr_contract.group_hr_contract_manager 1 1 1 1
access_gn_career_mission_career_rel_user gn_career_mission_career_rel_user model_gn_career_mission_career_rel base.group_user 1 0 0 0
access_gn_career_mission_career_rel_admin gn_career_mission_career_rel_admin model_gn_career_mission_career_rel hr_contract.group_hr_contract_manager 1 1 1 1
4 access_gn_career_task_user gn_career_task_user model_gn_career_task base.group_user 1 0 0 0
5 access_gn_career_task_admin gn_career_task_admin model_gn_career_task hr_contract.group_hr_contract_manager 1 1 1 1
6 access_gn_career_mission_user gn_career_mission_user model_gn_career_mission base.group_user 1 0 0 0
7 access_gn_career_mission_admin gn_career_mission_admin model_gn_career_mission hr_contract.group_hr_contract_manager 1 1 1 1
8 access_gn_career_mission_detail_user gn_career_mission_detail_user model_gn_career_mission_detail base.group_user 1 0 0 0
9 access_gn_career_mission_detail_admin gn_career_mission_detail_admin model_gn_career_mission_detail hr_contract.group_hr_contract_manager 1 1 1 1

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="gn_career_mission_detail_form_view" model="ir.ui.view">
<field name="name">gn_career.mission.detail.form</field>
<field name="model">gn_career.mission.detail</field>
<field name="arch" type="xml">
<form string="Détail des missions">
<sheet string="Détail de la mission">
<group>
<group>
<field name="career_id"/>
<field name="mission_id"/>
<field name="task_ids"/>
<field name="percentage"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="gn_career_mission_detail_tree_view" model="ir.ui.view">
<field name="name">gn_career.mission.detail.tree</field>
<field name="model">gn_career.mission.detail</field>
<field name="arch" type="xml">
<tree string="Mission Details">
<field name="mission_id"/>
<field name="percentage"/>
</tree>
</field>
</record>
<record id="gn_career_mission_detail_action" model="ir.actions.act_window">
<field name="name">Détails des missions</field>
<field name="res_model">gn_career.mission.detail</field>
<field name="view_mode">tree,form</field>
<field name="view_ids" eval="[(5, 0, 0), (0, 0, {'view_mode': 'tree', 'view_id': ref('gn_career_mission_detail_tree_view')}), (0, 0, {'view_mode': 'form', 'view_id': ref('gn_career_mission_detail_form_view')})]"/>
</record>
</odoo>

View File

@ -5,14 +5,29 @@
<field name="model">hr.contract</field>
<field name="priority" eval="30"/>
<field name="inherit_id" ref="hr_contract.hr_contract_view_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//div[@name='button_box']" position="inside">
<button name="open_associated_careers" type='object' class="oe_stat_button" icon="fa-money" groups="hr_contract.group_hr_contract_manager">
<field name="has_active_career" widget="statinfo" string="Fiche de poste"/>
</button>
</xpath>
</data>
</field>
</record>
<record id="gn_career.hr_contract_career" model="ir.ui.view">
<field name="name">hr.contract.form.gncareer.career</field>
<field name="model">hr.contract</field>
<field name="priority" eval="30"/>
<field name="inherit_id" ref="hr_contract.hr_contract_view_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//page[@name='information']" position="after">
<page string="Fiche de poste" name='career'>
<group name="missions">
<field name="active_career_id" widget='many2one' options="{'no_open': True, 'no_create': True}" domain="[('id','=',active_career_id)]"/>
<!-- Assuming mission_ids is a field in gn_career.career, display related missions -->
<!--<field name="active_career_id" string="Missions" widget="many2many_tags" options="{'no_create': True}" domain="[('id', 'in', active_career_id.mission_ids)]"/>-->
<page string="Fiche de poste">
<field name="active_career_id" invisible="1"/>
<group>
<field name="active_career_id" options="{'no_open': False}" string="Active Career"/>
<button name="open_active_career" type="object" class="oe_highlight" string="See Active Career"/>
</group>
</page>
</xpath>