Compare commits
20 Commits
old16.0
...
16-holiday
Author | SHA1 | Date |
---|---|---|
Florian Roger | 854bbeb0e4 | 7 months ago |
Florian Roger | 085819695f | 7 months ago |
Florian Roger | ec627b776f | 7 months ago |
Florian Roger | d7ffa017f4 | 7 months ago |
Florian Roger | 03aa1c0b2c | 7 months ago |
Florian Roger | b2fbc5fdc4 | 7 months ago |
Florian Roger | 2801953953 | 7 months ago |
Florian Roger | 8e8d04ad27 | 7 months ago |
Florian Roger | 230521005d | 7 months ago |
Florian Roger | 48ce980121 | 7 months ago |
Florian Roger | e4eb441bd0 | 7 months ago |
Florian Roger | a86dd2deda | 7 months ago |
Florian Roger | 6efa742956 | 7 months ago |
Florian Roger | 05f554ff53 | 7 months ago |
Florian Roger | 54359e0441 | 7 months ago |
Florian Roger | ea0421ee93 | 7 months ago |
Florian Roger | 5a41c45941 | 7 months ago |
Florian Roger | 5c925ca24f | 7 months ago |
Florian Roger | 6b0beaef61 | 8 months ago |
Florian Roger | d1a89cc008 | 8 months ago |
@ -0,0 +1,24 @@
|
||||
# GN CC
|
||||
|
||||
Module de gestion des conventions collectives par Le Garage Numérique.
|
||||
|
||||
## How to install
|
||||
|
||||
1. Clone this repository in your odoo's extra-modules folder (i.e. /mnt/extra-addons)
|
||||
2. Refresh list of Applications in UI
|
||||
3. Search for 'gn_cc' and click on **Install**
|
||||
|
||||
## Changelog
|
||||
|
||||
- v16.0.0.0.2 (2024/03/01):
|
||||
- Add 'l10n_fr_oca' as dependency
|
||||
- Add Readme
|
||||
- v16.0.0.0.1 (2024/02/29):
|
||||
- Creation of module
|
||||
|
||||
# Feature requests
|
||||
|
||||
- [] Add Convention Collective for "Organisme de Formation"
|
||||
- [] Add Convention Collective for "Centres Sociaux"
|
||||
- [] Add Convention Collective for "Prévention Spécialisée"
|
||||
|
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "France - Conventions Collective",
|
||||
"version": "16.0.0.0.2",
|
||||
"category": "France",
|
||||
"summary": "Configuration des accords de branche pour le France: Conventions Collectives",
|
||||
"author": "Le Garage Numérique",
|
||||
"maintainers": ["makayabou"],
|
||||
"website": "https://odoo.legaragenumerique.fr",
|
||||
"depends": [
|
||||
"hr",
|
||||
"hr_contract",
|
||||
"l10n_fr_oca",
|
||||
],
|
||||
"data": [
|
||||
"views/gn_cc_company.xml",
|
||||
"views/gn_cc_cc.xml",
|
||||
"data/gn_cc_cc.xml",
|
||||
"security/ir.model.access.csv"
|
||||
],
|
||||
"license": "LGPL-3",
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import gn_company
|
||||
from . import gn_cc
|
@ -0,0 +1,187 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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 ConventionCollective(models.Model):
|
||||
_name = "gn_cc.cc"
|
||||
_description = "Convention Collective"
|
||||
_order = 'idcc, name'
|
||||
|
||||
name = fields.Char(string='Nom complet de la Convention Collective', required=True)
|
||||
associated_companies = fields.One2many('res.company', string="Sociétés utilisant cette convention", inverse_name="cc")
|
||||
active = fields.Boolean(default=True)
|
||||
idcc = fields.Char(string="IDCC", default="3442")
|
||||
groups = fields.Text(string="Groupes d'emploi")
|
||||
criterias = fields.Text(string="Critères de description des groupes d'emploi")
|
||||
point_cat = fields.Text(string="Catégories de points")
|
||||
point_values = fields.One2many('gn_cc.cc.point_value', string="Valeurs du point", inverse_name="cc")
|
||||
descriptions = fields.One2many('gn_cc.cc.group.description', string="Description de groupes associés à la convention", inverse_name="cc")
|
||||
actual_values = fields.One2many('gn_cc.cc.point_value', string="Valeurs du point en vigueur", compute='_compute_actual_values')
|
||||
actual_descriptions = fields.One2many('gn_cc.cc.group.description', compute='_compute_actual_descriptions')
|
||||
coeffs = fields.One2many('gn_cc.cc.group.coeff', string="Coefficient minimum des groupes", inverse_name="cc")
|
||||
actual_coeffs = fields.One2many('gn_cc.cc.group.coeff', compute='_compute_actual_coeffs')
|
||||
|
||||
@api.depends('point_values')
|
||||
def _compute_actual_values(self):
|
||||
for cc in self:
|
||||
# Reset the value first
|
||||
cc.actual_values = [(5,)]
|
||||
|
||||
# This dict will hold the actual point_value ID for each 'name'
|
||||
actual_records = {}
|
||||
|
||||
# create a default comparison_date so we can use a context var to call this method in other modules (payslip)
|
||||
comparison_date = self.env.context.get('comparison_date', fields.Date.today())
|
||||
|
||||
# Iterate over all point_values to find the latest but not in the future
|
||||
for pv in cc.point_values.sorted(key='start_date', reverse=True):
|
||||
# If we haven't added a record for this 'name' yet, do it
|
||||
if pv.name not in actual_records and pv.start_date <= comparison_date:
|
||||
actual_records[pv.name] = pv
|
||||
|
||||
# Now, set the actual_values field to the IDs of the actual records
|
||||
actual_ids = [rec.id for rec in actual_records.values()]
|
||||
cc.actual_values = [(6, 0, actual_ids)]
|
||||
|
||||
@api.depends('descriptions')
|
||||
def _compute_actual_descriptions(self):
|
||||
for cc in self:
|
||||
# Reset the value first
|
||||
cc.actual_descriptions = [(5,)]
|
||||
|
||||
# This dict will hold the actual point_value ID for each 'name'
|
||||
actual_records = {}
|
||||
|
||||
# create a default comparison_date so we can use a context var to call this method in other modules (payslip)
|
||||
comparison_date = self.env.context.get('comparison_date', fields.Date.today())
|
||||
|
||||
# Iterate over all point_values to find the latest but not in the future
|
||||
for desc in cc.descriptions.sorted(key='start_date', reverse=True):
|
||||
key = (desc.group, desc.criteria)
|
||||
# If we haven't added a record for this 'name' yet, do it
|
||||
|
||||
if key not in actual_records and desc.start_date <= comparison_date:
|
||||
actual_records[key] = desc
|
||||
|
||||
# Now, set the actual_values field to the IDs of the actual records
|
||||
actual_ids = [rec.id for rec in actual_records.values()]
|
||||
cc.actual_descriptions = [(6, 0, actual_ids)]
|
||||
|
||||
@api.depends('coeffs')
|
||||
def _compute_actual_coeffs(self):
|
||||
for cc in self:
|
||||
# Reset the value first
|
||||
cc.actual_coeffs = [(5,)]
|
||||
|
||||
# This dict will hold the actual point_value ID for each 'name'
|
||||
actual_records = {}
|
||||
|
||||
# create a default comparison_date so we can use a context var to call this method in other modules (payslip)
|
||||
comparison_date = self.env.context.get('comparison_date', fields.Date.today())
|
||||
|
||||
# Iterate over all point_values to find the latest but not in the future
|
||||
for coeff in cc.coeffs.sorted(key='start_date', reverse=True):
|
||||
# If we haven't added a record for this 'name' yet, do it
|
||||
if coeff.group not in actual_records and coeff.start_date <= comparison_date:
|
||||
actual_records[coeff.group] = coeff
|
||||
|
||||
# Now, set the actual_values field to the IDs of the actual records
|
||||
actual_ids = [rec.id for rec in actual_records.values()]
|
||||
cc.actual_coeffs = [(6, 0, actual_ids)]
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
new_record = super(ConventionCollective, self).create(vals)
|
||||
self.env.user.company_id.write({'cc': new_record})
|
||||
return new_record
|
||||
|
||||
class ConventionCollectiveCoeffMin(models.Model):
|
||||
_name = "gn_cc.cc.group.coeff"
|
||||
_description = "Coefficient minimum pour le groupe d'emploi"
|
||||
_order = 'start_date'
|
||||
|
||||
@api.model
|
||||
def _default_cc(self):
|
||||
return self.env.user.company_id.cc
|
||||
|
||||
cc = fields.Many2one('gn_cc.cc', required=True, default='_default_cc', string="Convention collective associée")
|
||||
|
||||
@api.model
|
||||
def _get_groups_selection(self):
|
||||
_logger.info("Current compagnie: %s, Current CC: %s, Groups: %s", self.env.user.company_id.name, self.env.user.company_id.cc.idcc, self.env.user.company_id.cc.groups)
|
||||
if self.env.user.company_id.cc and self.env.user.company_id.cc.groups:
|
||||
groups_list = [(group.strip(), group.strip()) for group in self.env.user.company_id.cc.groups.split(';')]
|
||||
return groups_list
|
||||
else:
|
||||
return []
|
||||
|
||||
start_date = fields.Date('From', required=True, default=lambda self: fields.Date.today())
|
||||
group = fields.Selection(selection='_get_groups_selection', required=True, string="Groupe associé au coefficient")
|
||||
coeff_min = fields.Integer(string="Coefficient Minimum", required=True)
|
||||
|
||||
|
||||
class ConventionCollectiveGroupDescription(models.Model):
|
||||
_name = "gn_cc.cc.group.description"
|
||||
_description = "Descriptions des groupes d'emploi"
|
||||
_order = 'start_date'
|
||||
|
||||
@api.model
|
||||
def _default_cc(self):
|
||||
return self.env.user.company_id.cc
|
||||
|
||||
@api.model
|
||||
def _get_groups_selection(self):
|
||||
if self.env.user.company_id.cc and self.env.user.company_id.cc.groups:
|
||||
groups_list = [(group.strip(), group.strip()) for group in self.env.user.company_id.cc.groups.split(';')]
|
||||
return groups_list
|
||||
else:
|
||||
return []
|
||||
|
||||
@api.model
|
||||
def _get_criterias_selection(self):
|
||||
if self.env.user.company_id.cc and self.env.user.company_id.cc.criterias:
|
||||
criterias_list = [(criteria.strip(), criteria.strip()) for criteria in self.env.user.company_id.cc.criterias.split(';')]
|
||||
return criterias_list
|
||||
else:
|
||||
return []
|
||||
|
||||
cc = fields.Many2one('gn_cc.cc', required=True, default=_default_cc, string="Convention collective associée")
|
||||
start_date = fields.Date('From', required=True, default=lambda self: fields.Date.today())
|
||||
group = fields.Selection(selection='_get_groups_selection', required=True, string="Groupe")
|
||||
criteria = fields.Selection(selection='_get_criterias_selection', required=True, string="Critère de classification")
|
||||
description = fields.Text(required=True)
|
||||
|
||||
|
||||
class ConventionCollectivePointValue(models.Model):
|
||||
_name = "gn_cc.cc.point_value"
|
||||
_description = "Valeur du point"
|
||||
_order = 'start_date, cc'
|
||||
|
||||
@api.model
|
||||
def _default_cc(self):
|
||||
return self.env.user.company_id.cc
|
||||
|
||||
@api.model
|
||||
def _get_point_cat_selection(self):
|
||||
if self.env.user.company_id.cc and self.env.user.company_id.cc.point_cat:
|
||||
point_cat_list = [(cat.strip(), cat.strip()) for cat in self.env.user.company_id.cc.point_cat.split(';')]
|
||||
return point_cat_list
|
||||
else:
|
||||
return []
|
||||
|
||||
start_date = fields.Date('From', required=True)
|
||||
cc = fields.Many2one('gn_cc.cc', required=True, default=_default_cc, string="Convention collective associée")
|
||||
name = fields.Selection(selection='_get_point_cat_selection', required=True, string="Catégorie de point")
|
||||
value = fields.Monetary(string='Valeur du Point', help='Valeur du point défini par les partenaires sociaux', required=True)
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
string='Currency',
|
||||
required=True,
|
||||
default=lambda self: self.env.user.company_id.currency_id.id,
|
||||
help="Currency"
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_gn_cc_cc_user,gn_cc_cc_user,model_gn_cc_cc,base.group_user,1,0,0,0
|
||||
access_gn_cc_cc_admin,gn_cc_cc_admin,model_gn_cc_cc,hr_contract.group_hr_contract_manager,1,1,1,1
|
||||
access_gn_cc_cc_group_coeff_user,gn_cc_cc_group_coeff_user,model_gn_cc_cc_group_coeff,base.group_user,1,0,0,0
|
||||
access_gn_cc_cc_group_coeff_admin,gn_cc_cc_group_coeff_admin,model_gn_cc_cc_group_coeff,hr_contract.group_hr_contract_manager,1,1,1,1
|
||||
access_gn_cc_cc_group_description_user,gn_cc_cc_group_description_user,model_gn_cc_cc_group_description,base.group_user,1,0,0,0
|
||||
access_gn_cc_cc_group_description_admin,gn_cc_cc_group_description_admin,model_gn_cc_cc_group_description,hr_contract.group_hr_contract_manager,1,1,1,1
|
||||
access_gn_cc_cc_point_value_user,gn_cc_cc_point_value_user,model_gn_cc_cc_point_value,base.group_user,1,0,0,0
|
||||
access_gn_cc_cc_point_value_admin,gn_cc_cc_point_value_admin,model_gn_cc_cc_point_value,hr_contract.group_hr_contract_manager,1,1,1,1
|
|
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="gn_cc_form_view" model="ir.ui.view">
|
||||
<field name="name">gn_cc.cc.form</field>
|
||||
<field name="model">gn_cc.cc</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Conventions Collectives">
|
||||
<sheet string="Convention Collective">
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Nom complet de la convention collective" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="idcc" />
|
||||
<field name="groups" placeholder="Liste des groupes, séparés par un point-virgule"/>
|
||||
<field name="criterias" placeholder="Liste des critères de classement des groupes, séparés par un retour à la ligne"/>
|
||||
<field name="point_cat" placeholder="Liste des catégories de points, séparés par un retour à la ligne"/>
|
||||
|
||||
<field name="actual_values" context="{'default_cc': active_id}" options="{'create': True, 'delete': True}">
|
||||
<tree editable="bottom">
|
||||
<field name="name" help="catégorie de point"/>
|
||||
<field name="start_date"/>
|
||||
<field name="value"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="actual_descriptions" context="{'default_cc': active_id}" widget="one2many_list" options="{'create': True, 'delete': True}">
|
||||
<tree editable="bottom">
|
||||
<field name="start_date"/>
|
||||
<field name="group"/>
|
||||
<field name="criteria"/>
|
||||
<field name="description"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="actual_coeffs" context="{'default_cc': active_id}" widget="one2many_list" options="{'create': True, 'delete': True}">
|
||||
<tree editable="bottom">
|
||||
<field name="start_date"/>
|
||||
<field name="group"/>
|
||||
<field name="coeff_min"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="gn_cc.cc_configuration" model="ir.actions.act_window">
|
||||
<field name="name">Conventions Collectives</field>
|
||||
<field name="res_model">gn_cc.cc</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<record id="gn_cc.cc_group_coeff_configuration" model="ir.actions.act_window">
|
||||
<field name="name">Coefficient minimum</field>
|
||||
<field name="res_model">gn_cc.cc.group.coeff</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<record id="gn_cc.cc_group_description_configuration" model="ir.actions.act_window">
|
||||
<field name="name">Description du groupe</field>
|
||||
<field name="res_model">gn_cc.cc.group.description</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<record id="gn_cc.cc_point_value_configuration" model="ir.actions.act_window">
|
||||
<field name="name">Valeur du point</field>
|
||||
<field name="res_model">gn_cc.cc.point_value</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
</odoo>
|
@ -0,0 +1,19 @@
|
||||
# GN Holidays
|
||||
|
||||
Module de gestion des congés et absences des employés
|
||||
|
||||
## How to install
|
||||
|
||||
1. Clone this repository in your odoo's extra-modules folder (i.e. /mnt/extra-addons)
|
||||
2. Refresh list of Applications in UI
|
||||
3. Search for 'gn_holidays' and click on **Install**
|
||||
|
||||
## Changelog
|
||||
|
||||
- v16.0.0.0.1 (2024/03/01):
|
||||
- Création du module
|
||||
- Ajouts des jours feriés pour 2024
|
||||
- Ajout des types d'absence
|
||||
|
||||
## Issues
|
||||
- [] Need prevention mechanism when CP or Compensatory Day is asked on a Public Holiday (cf issue #8)
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "France - Congés",
|
||||
"version": "16.0.0.0.1",
|
||||
"category": "HR",
|
||||
"summary": "Configuration des congés et absences",
|
||||
"author": "Le Garage Numérique",
|
||||
"maintainers": ["makayabou"],
|
||||
"website": "https://odoo.legaragenumerique.fr",
|
||||
"depends": [
|
||||
"hr",
|
||||
"hr_contract",
|
||||
"l10n_fr_oca",
|
||||
"hr_work_entry",
|
||||
"hr_work_entry_holidays",
|
||||
"hr_holidays_public",
|
||||
],
|
||||
"data": [
|
||||
"data/gn_holidays_public.xml",
|
||||
"data/gn_holidays.xml",
|
||||
],
|
||||
"license": "LGPL-3",
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Work Entry Type -->
|
||||
<record id="hr_work_entry_contract.work_entry_type_compensatory" model="hr.work.entry.type">
|
||||
<field name="display_name">Congé compensatoire (récup')</field>
|
||||
<field name="code">RTT</field>
|
||||
<field name="color">15</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_home_working" model="hr.work.entry.type">
|
||||
<field name="name">Télé-travail</field>
|
||||
<field name="code">TT</field>
|
||||
<field name="color">1</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_unpaid_leave" model="hr.work.entry.type">
|
||||
<field name="name">Absence non-rémunérée</field>
|
||||
<field name="color">2</field>
|
||||
<field name="code">ABS</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_sick_leave" model="hr.work.entry.type">
|
||||
<field name="name">Congé Maladie</field>
|
||||
<field name="code">AM</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
<field name="color">9</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_legal_leave" model="hr.work.entry.type">
|
||||
<field name="name">Congé payé</field>
|
||||
<field name="code">CP</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
<field name="color">6</field>
|
||||
</record>
|
||||
<!--Congés payés-->
|
||||
<record id="hr_holidays.holiday_status_cl" model="hr.leave.type">
|
||||
<field name="name">Paid Time Off</field>
|
||||
<field name="requires_allocation">yes</field>
|
||||
<field name="employee_requests">no</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
|
||||
<field name="allocation_notif_subtype_id" ref="hr_holidays.mt_leave_allocation"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="request_unit">day</field>
|
||||
<field name="support_document" eval="False"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_legal_leave"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_14"/>
|
||||
<field name="color">2</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
|
||||
<!-- Arrêt maladie -->
|
||||
<record id="hr_holidays.holiday_status_sl" model="hr.leave.type">
|
||||
<field name="name">Sick Time Off</field>
|
||||
<field name="requires_allocation">no</field>
|
||||
<field name="color_name">red</field>
|
||||
<field name="leave_validation_type">no_validation</field>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_sick"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="request_unit">day</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="exclude_public_holidays" eval="False"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_sick_leave"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_22"/>
|
||||
<field name="color">3</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
|
||||
<!-- Compensatory Days -->
|
||||
<record id="hr_holidays.holiday_status_comp" model="hr.leave.type">
|
||||
<field name="name">Compensatory Days</field>
|
||||
<field name="requires_allocation">yes</field>
|
||||
<field name="employee_requests">yes</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_compensatory"/>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_4"/>
|
||||
<field name="color">4</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
|
||||
<!--Absence non-rémunérée -->
|
||||
<record id="hr_holidays.holiday_status_unpaid" model="hr.leave.type">
|
||||
<field name="name">Unpaid</field>
|
||||
<field name="requires_allocation">no</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="unpaid" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_unpaid_leave"/>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_28"/>
|
||||
<field name="color">5</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
|
||||
<!-- Plan de cumul des congés payés-->
|
||||
<record id="cumul_cp" model="hr.leave.accrual.plan">
|
||||
<field name="name">Cumul des congés payés</field>
|
||||
<field name="time_off_type_id" ref="hr_holidays.holiday_status_cl"/>
|
||||
</record>
|
||||
|
||||
<!-- Régle de cumul des Congés payés-->
|
||||
<record id="cumul_standard" model="hr.leave.accrual.level">
|
||||
<field name="start_count">0</field>
|
||||
<field name="start_type">month</field>
|
||||
<field name="is_based_on_worked_time" eval="True"/>
|
||||
<field name="added_value">2.5</field>
|
||||
<field name="added_value_type">days</field>
|
||||
<field name="frequency">monthly</field>
|
||||
<field name="maximum_leave">90</field>
|
||||
<field name="action_with_unused_accruals">postponed</field>
|
||||
<field name="postpone_max_days">60</field>
|
||||
<field name="accrual_plan_id" ref="gn_holidays.cumul_cp"/>
|
||||
</record>
|
||||
</data>
|
||||
<delete model="hr.work.entry.type" id="hr_work_entry_contract.work_entry_type_leave"/>
|
||||
</odoo>
|
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Jour fériés 2024 -->
|
||||
<record id="jours_feries_2024" model="hr.holidays.public">
|
||||
<field name="year">2024</field>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
</record>
|
||||
<record id="jour_ferie_jour_de_l_an" model="hr.holidays.public.line">
|
||||
<field name="name">Jour de l'an</field>
|
||||
<field name="date" eval="'2024-01-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_lundi_de_paques" model="hr.holidays.public.line">
|
||||
<field name="name">Lundi de Pâques</field>
|
||||
<field name="date" eval="'2024-04-01'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_fete_du_travail" model="hr.holidays.public.line">
|
||||
<field name="name">Fête du Travail</field>
|
||||
<field name="date" eval="'2024-05-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_victoire_1945" model="hr.holidays.public.line">
|
||||
<field name="name">Victoire 1945</field>
|
||||
<field name="date" eval="'2024-05-08'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_ascension" model="hr.holidays.public.line">
|
||||
<field name="name">Ascension</field>
|
||||
<field name="date" eval="'2024-05-09'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_pentecote" model="hr.holidays.public.line">
|
||||
<field name="name">Pentecôte</field>
|
||||
<field name="date" eval="'2024-05-20'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_fete_nationale" model="hr.holidays.public.line">
|
||||
<field name="name">Fête Nationale</field>
|
||||
<field name="date" eval="'2024-07-14'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_assomption" model="hr.holidays.public.line">
|
||||
<field name="name">Assomption</field>
|
||||
<field name="date" eval="'2024-08-15'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_toussaint" model="hr.holidays.public.line">
|
||||
<field name="name">Toussaint</field>
|
||||
<field name="date" eval="'2024-11-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_armistrice_1918" model="hr.holidays.public.line">
|
||||
<field name="name">Armistrice 1918</field>
|
||||
<field name="date" eval="'2024-11-11'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_noel" model="hr.holidays.public.line">
|
||||
<field name="name">Jour de Noël</field>
|
||||
<field name="date" eval="'2024-12-25'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="gn_payroll.cc_1418" model="gn_payroll.cc">
|
||||
<field name="name">Convention Eclat</field>
|
||||
<field name="idcc">1418</field>
|
||||
</record>
|
||||
</odoo>
|
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Work Entry Type -->
|
||||
<record id="hr_work_entry_contract.work_entry_type_compensatory" model="hr.work.entry.type">
|
||||
<field name="display_name">Congé compensatoire (récup')</field>
|
||||
<field name="code">RTT</field>
|
||||
<field name="color">15</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_home_working" model="hr.work.entry.type">
|
||||
<field name="name">Télé-travail</field>
|
||||
<field name="code">TT</field>
|
||||
<field name="color">1</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_unpaid_leave" model="hr.work.entry.type">
|
||||
<field name="name">Absence non-rémunérée</field>
|
||||
<field name="color">2</field>
|
||||
<field name="code">ABS</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_sick_leave" model="hr.work.entry.type">
|
||||
<field name="name">Congé Maladie</field>
|
||||
<field name="code">AM</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
<field name="color">9</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_work_entry_contract.work_entry_type_legal_leave" model="hr.work.entry.type">
|
||||
<field name="name">Congé payé</field>
|
||||
<field name="code">CP</field>
|
||||
<field name="is_leave" eval="True"/>
|
||||
<field name="color">6</field>
|
||||
</record>
|
||||
<!--Congés payés-->
|
||||
<record id="hr_holidays.holiday_status_cl" model="hr.leave.type">
|
||||
<field name="name">Paid Time Off</field>
|
||||
<field name="requires_allocation">yes</field>
|
||||
<field name="employee_requests">no</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
|
||||
<field name="allocation_notif_subtype_id" ref="hr_holidays.mt_leave_allocation"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="request_unit">day</field>
|
||||
<field name="support_document" eval="False"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_legal_leave"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_14"/>
|
||||
<field name="color">2</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
|
||||
<!-- Arrêt maladie -->
|
||||
<record id="hr_holidays.holiday_status_sl" model="hr.leave.type">
|
||||
<field name="name">Sick Time Off</field>
|
||||
<field name="requires_allocation">no</field>
|
||||
<field name="color_name">red</field>
|
||||
<field name="leave_validation_type">no_validation</field>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_sick"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="request_unit">day</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="exclude_public_holidays" eval="False"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_sick_leave"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_22"/>
|
||||
<field name="color">3</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
|
||||
<!-- Compensatory Days -->
|
||||
<record id="hr_holidays.holiday_status_comp" model="hr.leave.type">
|
||||
<field name="name">Compensatory Days</field>
|
||||
<field name="requires_allocation">yes</field>
|
||||
<field name="employee_requests">yes</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_compensatory"/>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_4"/>
|
||||
<field name="color">4</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
|
||||
<!--Absence non-rémunérée -->
|
||||
<record id="hr_holidays.holiday_status_unpaid" model="hr.leave.type">
|
||||
<field name="name">Unpaid</field>
|
||||
<field name="requires_allocation">no</field>
|
||||
<field name="leave_validation_type">hr</field>
|
||||
<field name="allocation_validation_type">officer</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="unpaid" eval="True"/>
|
||||
<field name="time_type">leave</field>
|
||||
<field name="support_document" eval="True"/>
|
||||
<field name="exclude_public_holidays" eval="True"/>
|
||||
<field name="work_entry_type_id" ref="hr_work_entry_contract.work_entry_type_unpaid_leave"/>
|
||||
<field name="leave_notif_subtype_id" ref="hr_holidays.mt_leave_unpaid"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="icon_id" ref="hr_holidays.icon_28"/>
|
||||
<field name="color">5</field>
|
||||
<field name="company_id" eval="False"/> <!-- Explicitely set to False for it to be available to all companies -->
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
|
||||
<!-- Plan de cumul des congés payés-->
|
||||
<record id="cumul_cp" model="hr.leave.accrual.plan">
|
||||
<field name="name">Cumul des congés payés</field>
|
||||
<field name="time_off_type_id" ref="hr_holidays.holiday_status_cl"/>
|
||||
</record>
|
||||
|
||||
<!-- Régle de cumul des Congés payés-->
|
||||
<record id="cumul_standard" model="hr.leave.accrual.level">
|
||||
<field name="start_count">0</field>
|
||||
<field name="start_type">month</field>
|
||||
<field name="is_based_on_worked_time" eval="True"/>
|
||||
<field name="added_value">2.5</field>
|
||||
<field name="added_value_type">days</field>
|
||||
<field name="frequency">monthly</field>
|
||||
<field name="maximum_leave">90</field>
|
||||
<field name="action_with_unused_accruals">postponed</field>
|
||||
<field name="postpone_max_days">60</field>
|
||||
<field name="accrual_plan_id" ref="gn_payroll.cumul_cp"/>
|
||||
</record>
|
||||
</data>
|
||||
<delete model="hr.work.entry.type" id="hr_work_entry_contract.work_entry_type_leave"/>
|
||||
</odoo>
|
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Jour fériés 2024 -->
|
||||
<record id="jours_feries_2024" model="hr.holidays.public">
|
||||
<field name="year">2024</field>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
</record>
|
||||
<record id="jour_ferie_jour_de_l_an" model="hr.holidays.public.line">
|
||||
<field name="name">Jour de l'an</field>
|
||||
<field name="date" eval="'2024-01-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_lundi_de_paques" model="hr.holidays.public.line">
|
||||
<field name="name">Lundi de Pâques</field>
|
||||
<field name="date" eval="'2024-04-01'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_fete_du_travail" model="hr.holidays.public.line">
|
||||
<field name="name">Fête du Travail</field>
|
||||
<field name="date" eval="'2024-05-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_victoire_1945" model="hr.holidays.public.line">
|
||||
<field name="name">Victoire 1945</field>
|
||||
<field name="date" eval="'2024-05-08'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_ascension" model="hr.holidays.public.line">
|
||||
<field name="name">Ascension</field>
|
||||
<field name="date" eval="'2024-05-09'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_pentecote" model="hr.holidays.public.line">
|
||||
<field name="name">Pentecôte</field>
|
||||
<field name="date" eval="'2024-05-20'"/>
|
||||
<field name="variable_date" eval="True"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_fete_nationale" model="hr.holidays.public.line">
|
||||
<field name="name">Fête Nationale</field>
|
||||
<field name="date" eval="'2024-07-14'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_assomption" model="hr.holidays.public.line">
|
||||
<field name="name">Assomption</field>
|
||||
<field name="date" eval="'2024-08-15'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_toussaint" model="hr.holidays.public.line">
|
||||
<field name="name">Toussaint</field>
|
||||
<field name="date" eval="'2024-11-01'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_armistrice_1918" model="hr.holidays.public.line">
|
||||
<field name="name">Armistrice 1918</field>
|
||||
<field name="date" eval="'2024-11-11'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
<record id="jour_ferie_noel" model="hr.holidays.public.line">
|
||||
<field name="name">Jour de Noël</field>
|
||||
<field name="date" eval="'2024-12-25'"/>
|
||||
<field name="variable_date" eval="False"/>
|
||||
<field name="year_id" ref="jours_feries_2024"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import gn_payroll_cc
|
||||
from . import gn_payroll_company
|
||||
from . import gn_payroll_employee
|
||||
from . import gn_payroll_contract
|
||||
from . import gn_payroll_employee
|
||||
#from . import gn_payroll_payslip
|
@ -1,17 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ConventionCollective(models.Model):
|
||||
_name = "gn_payroll.cc"
|
||||
_description = "Convention Collective"
|
||||
_order = 'idcc, name'
|
||||
|
||||
def copy(self, default=None):
|
||||
raise UserError(_('Duplicating a company is not allowed. Please create a new company instead.'))
|
||||
|
||||
name = fields.Char(string='Nom complet de la Convention Collective', required=True, store=True, readonly=False)
|
||||
active = fields.Boolean(default=True)
|
||||
idcc = fields.Integer(string="IDCC", help='Used to order Conventions Collectives in the switcher', default=10)
|
@ -0,0 +1,226 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, api
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import date, datetime
|
||||
from odoo.exceptions import ValidationError
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class GnCalendarEvent(models.Model):
|
||||
_inherit = "calendar.event"
|
||||
is_entretien = fields.Boolean(string="Concerne un entretien professionnel", default=False)
|
||||
entretien_id = fields.Many2one("gn_payroll.hr.contract.entretien", string="Entretien professionnel associé")
|
||||
entretien_ids = fields.Many2one("gn_payroll.hr.contract.entretien", string="Entretiens professionnels associés")
|
||||
|
||||
class GnHrContract(models.Model):
|
||||
_inherit = "hr.contract"
|
||||
|
||||
previous_contract_id = fields.Many2one("hr.contract", string="Contrat précédent (en cas d'avenant, de renouvellement ou de changement de poste)", default=False)
|
||||
contract_lineage_sequence_number = fields.Integer(string="Numéro de séquence dans l'historique du salarié", default=0)
|
||||
computed_wage = fields.Integer(string="Salaire négocié (en fonction des éléments de la fiche de poste)", compute='_compute_wage', readonly=True, store=True)
|
||||
|
||||
#entretien_type_ids = fields.Many2many('gn_payroll.hr.contract.entretien.type', string="Catégories d'entretiens prévues au contrat")
|
||||
#entretien_sequence_number = fields.Integer(string="Entretien Sequence Number", default=1)
|
||||
|
||||
entretien_ids = fields.One2many('gn_payroll.hr.contract.entretien', inverse_name='main_contract_id', string="Entretiens liés au contrat")
|
||||
|
||||
career_ids = fields.One2many('gn_payroll.hr.contract.career', readonly=True, inverse_name='contract_id', string="Fiche de poste associée")
|
||||
|
||||
# def update_entretiens_names(self):
|
||||
# for contract in self:
|
||||
# sequence_number = 1
|
||||
# for entretien in contract.entretien_ids.sorted('start'):
|
||||
# entretien.name = 'Entretien n°{}: {}'.format(sequence_number, entretien.type_id.name )
|
||||
# sequence_number += 1
|
||||
|
||||
# @api.model
|
||||
# def _get_groups_selection(self):
|
||||
# if self.env.user.company_id.cc and self.env.user.company_id.cc.groups:
|
||||
# groups_list = [(group.strip(), group.strip()) for group in self.env.user.company_id.cc.groups.split(';')]
|
||||
# return groups_list
|
||||
# else:
|
||||
# return []
|
||||
|
||||
|
||||
# Pas à supprimer complètement, mais à reprendre
|
||||
@api.depends('indice', 'classification_group')
|
||||
def _compute_wage(self):
|
||||
for contract in self:
|
||||
contract.computed_wage = contract.wage
|
||||
return True
|
||||
if contract.company_id.cc and contract.company_id.cc.idcc =="3442":
|
||||
group_coeff = cc.actual_coeffs.filtered(lambda r: r.group == contract.classification_group).ensure_one()['coeff_min']
|
||||
if group_coeff > employee.contract_id.indice:
|
||||
raise UserError("L'indice minimum conventionnel pour le poste est %s, veuillez ajuster l'indice du contract en conséquence.", group_coeff)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
contract = super(GnHrContract, self).create(vals)
|
||||
if not contract.parent_contract_id:
|
||||
cc_id = contract.company_id.cc.id
|
||||
entretien_types = self.env['gn_payroll.hr.contract.entretien.type'].search([
|
||||
('cc_ids', 'in', [cc_id]),
|
||||
('auto', '=', True)
|
||||
])
|
||||
for entretien_type in entretien_types:
|
||||
self.env['gn_payroll.hr.contract.entretien'].create({
|
||||
'employee_id': contract.employee_id.user_partner_id.id,
|
||||
'main_contract_id': contract.id,
|
||||
'type_id': entretien_type.id,
|
||||
})
|
||||
#contract.entretien_sequence_number += 1
|
||||
contract_lineage_sequence_number += 1
|
||||
return contract
|
||||
|
||||
|
||||
class EntretienType(models.Model):
|
||||
_name='gn_payroll.hr.contract.entretien.type'
|
||||
_description = "Type d'entretien d'évaluation ou de modification du contrat"
|
||||
|
||||
cc_ids = fields.Many2many('gn_payroll.cc', string="Conventions collectives rattachées")
|
||||
name = fields.Char(string="Type de l'entretien", required = True)
|
||||
auto = fields.Boolean("Est généré automatiquement à la création du contrat")
|
||||
start_point = fields.Selection(string="Point de départ des entretiens", selection=[('endofyear', "En fin d'année"), ('contract', "À la date anniversaire du contrat"), ('absence', "Au retour d'un congé long")])
|
||||
month_delay = fields.Integer(string="Nombre de mois entre chaque entretien")
|
||||
generate_subcontract = fields.Boolean("Génère la création d'un avenant au contrat")
|
||||
parent_id = fields.Many2one('gn_payroll.hr.contract.entretien.type', string="Type d'entretien parent", ondelete="cascade")
|
||||
child_ids = fields.One2many('gn_payroll.hr.contract.entretien.type', 'parent_id', string="Types d'entretien enfants")
|
||||
|
||||
|
||||
@api.constrains('parent_id')
|
||||
def _check_parent_id(self):
|
||||
for record in self:
|
||||
if record.parent_id == record:
|
||||
raise ValidationError("A record cannot select itself as a parent.")
|
||||
|
||||
if record.parent_id and record.parent_id.parent_id:
|
||||
raise ValidationError("You cannot select a parent type which already has a parent.")
|
||||
|
||||
@api.onchange('parent_id')
|
||||
def _onchange_parent_id(self):
|
||||
if self.parent_id:
|
||||
if self.parent_id == self:
|
||||
self.parent_id = False
|
||||
return {
|
||||
'warning': {
|
||||
'title': "Invalid Parent Selection",
|
||||
'message': "A record cannot select itself as a parent.",
|
||||
},
|
||||
'domain': {'parent_id': domain}
|
||||
}
|
||||
if self.parent_id.parent_id:
|
||||
self.parent_id = False
|
||||
return {
|
||||
'warning': {
|
||||
'title': "Invalid Parent Selection",
|
||||
'message': "You cannot select a parent type which already has a parent.",
|
||||
}
|
||||
}
|
||||
|
||||
class Entretien(models.Model):
|
||||
_name = 'gn_payroll.hr.contract.entretien'
|
||||
_description = "Entretien légal d'évaluation ou de modification du contrat"
|
||||
|
||||
ref = fields.Char(string="Référence", readonly=True)
|
||||
name = fields.Char(string="Titre", readonly=True)
|
||||
employee_id = fields.Many2one('res.partner', string="Employé", required=True, domain=[("employee_ids", "!=", False)], relation="contract_entretien_employee_rel")
|
||||
other_participant_ids = fields.Many2many('res.partner', string="Autres participants à l'entretien (délégué salariale, etc.)", relation="contract_entretien_other_participant_rel")
|
||||
interviewer_id = fields.Many2one('res.partner', domain=[("employee_ids", "!=", False)], string="Interviewer", relation="contract_entretien_interviewer_rel")
|
||||
other_interviewer_ids = fields.Many2many('res.partner', domain=[("employee_ids", "!=", False)], string="Participants à l'entretien", relation="contract_entretien_other_interviewer_rel")
|
||||
main_contract_id = fields.Many2one('hr.contract', string = "Contrat concerné", required=True)
|
||||
running_contract_id = fields.Many2one('hr.contract', string="Avenant concerné")
|
||||
|
||||
type_id = fields.Many2one('gn_payroll.hr.contract.entretien.type', string="Type d'entretien", required=True)
|
||||
first_date = fields.Date(string="Premier entretien", compute='_compute_first_date', store=True)
|
||||
next_date = fields.Date(string="Date du prochain entretien", compute='_compute_next_entretien_date', store=True)
|
||||
|
||||
report = fields.Html(string="Compte-rendu")
|
||||
|
||||
event_ids = fields.One2many('calendar.event', 'entretien_ids', string="Rendez-vous programmés")
|
||||
event_id = fields.One2many('calendar.event', 'entretien_id', string="Rendez-vous programmé", compute='_get_date_from_event', store=True)
|
||||
start = fields.Datetime("Date et heure du rendez-vous", compute='_get_date_from_event', store=True)
|
||||
|
||||
generate_subcontract = fields.Boolean(
|
||||
string="Génére la création d'un avenant",
|
||||
default=lambda self: self._get_default_generate_subcontract()
|
||||
)
|
||||
generation_start = fields.Datetime(string="Date de prise en compte des aménagements")
|
||||
generated_contract_id = fields.Many2one('hr.contract', string="Avenant généré")
|
||||
generated_career_id = fields.Many2one('gn_payroll.hr.contract.career', string="Fiche de poste")
|
||||
|
||||
def _get_default_generate_subcontract(self):
|
||||
return self.type_id.generate_subcontract if self.type_id else False
|
||||
|
||||
def update_main_contract(self):
|
||||
# Updates entretien's num by date for employee,
|
||||
# Called in _get_date_from_event on event_ids access
|
||||
for entretien in self:
|
||||
if entretien['main_contract_id']:
|
||||
contract = self.env['hr.contract'].browse(entretien['main_contract_id'].id)
|
||||
contract.update_entretiens_names()
|
||||
|
||||
@api.depends('type_id.start_point', 'type_id.month_delay')
|
||||
def _compute_first_date(self):
|
||||
for entretien in self:
|
||||
if entretien.type_id and entretien.type_id.start_point:
|
||||
start_point = entretien.type_id.start_point
|
||||
if start_point == "contract" and entretien.main_contract_id.date_start and entretien.type_id.month_delay:
|
||||
contract_start_date = fields.Date.from_string(entretien.main_contract_id.date_start)
|
||||
entretien.first_date = contract_start_date + relativedelta(months=+entretien.type_id.month_delay)
|
||||
elif start_point == "endofyear":
|
||||
today = fields.Date.today()
|
||||
entretien.first_date = date(today.year, 12, today.day)
|
||||
elif start_point == "absence":
|
||||
entretien.first_date = fields.Date.today()
|
||||
|
||||
@api.depends('event_ids')
|
||||
def _get_date_from_event(self):
|
||||
for entretien in self:
|
||||
try:
|
||||
if len(entretien.event_ids) > 0 and entretien.event_ids[0].start:
|
||||
#entretien.event_id = self.env['calendar.event'].browse(entretien.event_ids[0].id)
|
||||
entretien.event_id = entretien.event_ids[0]
|
||||
_logger.info("Entretien has event_id: %s", entretien.event_id)
|
||||
entretien.start = datetime.combine(entretien.event_ids[0].start, datetime.min.time())
|
||||
else:
|
||||
entretien.start = datetime.combine(entretien.first_date, datetime.min.time()) if entretien.first_date else datetime.now()
|
||||
except Exception as e:
|
||||
_logger.error("Error occurred while setting start date: %s", e)
|
||||
entretien.start = datetime.combine(fields.Date.today(), datetime.min.time())
|
||||
|
||||
_logger.info("Date defined as start in entretien: %s", entretien.start)
|
||||
self.update_main_contract()
|
||||
|
||||
@api.depends('first_date', 'type_id.month_delay')
|
||||
def _compute_next_entretien_date(self):
|
||||
for entretien in self:
|
||||
if entretien.first_date and entretien.type_id.month_delay:
|
||||
next_entretien_date = fields.Date.from_string(entretien.first_date) + relativedelta(months=entretien.type_id.month_delay)
|
||||
entretien.next_date = fields.Date.to_string(next_entretien_date)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
|
||||
result = super(Entretien, self).create(vals)
|
||||
employee_type = self.env['res.partner'].browse(vals['employee_id'])
|
||||
_logger.info("Employee id is : %s", employee_type.company_type)
|
||||
# Generate a sequence number for the name field
|
||||
if not vals.get('ref'):
|
||||
vals['ref'] = self.env['ir.sequence'].next_by_code('gn_payroll.hr.contract.entretien') or "New"
|
||||
_logger.info("Ref for entretien : %s", vals['ref'])
|
||||
|
||||
# Fetch contract to regenerated associated entretiens names
|
||||
if vals.get('main_contract_id'):
|
||||
contract = self.env['hr.contract'].browse(vals['main_contract_id'])
|
||||
contract.update_entretiens_names()
|
||||
|
||||
if vals.get('event_ids'):
|
||||
existing_entretien = self.search([('event_ids', 'in', vals['event_id'])], limit=1)
|
||||
if existing_entretien:
|
||||
raise ValidationError("An entretien is already associated with this event.")
|
||||
|
||||
return result
|
||||
|
@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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 ContractCareer(models.Model):
|
||||
_name = "gn_payroll.career"
|
||||
_description = "Analyse du poste"
|
||||
_order = 'start_date, employee_id'
|
||||
|
||||
start_date = fields.Date('From', required=True, default=lambda self: fields.Date.today())
|
||||
contract_id = fields.Many2one('gn_payroll.hr.contract', 'career_id', required=True, string="Contrat ou Avenant Associé")
|
||||
main_contract_id = fields.Many2one('gn_payroll.hr.contract', compute='_compute_main_contract', string="Contract principal associé")
|
||||
|
||||
entretien_id = fields.Many2one('gn_payroll.hr.contract.entretien', string="Entretien professionnel associé")
|
||||
|
||||
classification_group = fields.Selection(selection='_get_groups_selection', string="Groupe associé au coefficient")
|
||||
indice = fields.Integer(string="indice du salaire négocié (nombre de points)")
|
||||
|
||||
|
||||
@api.constrains('entretien_id')
|
||||
def _check_entretien_uniqueness(self):
|
||||
for record in self:
|
||||
if record.entretien_id:
|
||||
# Check if any other career records have the same entretien_id
|
||||
existing = self.search([
|
||||
('id', '!=', record.id),
|
||||
('entretien_id', '=', record.entretien_id.id),
|
||||
])
|
||||
if existing:
|
||||
raise ValidationError("An entretien can only be associated with one career.")
|
||||
|
||||
@api.constrains('entretien_id')
|
||||
def _check_contract_uniqueness(self):
|
||||
for record in self:
|
||||
if record.contract_id:
|
||||
# Check if any other career records have the same entretien_id
|
||||
existing = self.search([
|
||||
('id', '!=', record.id),
|
||||
('contract_id', '=', record.contract_id.id),
|
||||
])
|
||||
if existing:
|
||||
raise ValidationError("An contract can only be associated with one career.")
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
career = super(ContractCareer, self).create(vals)
|
||||
contract_id = vals.get('contract_id')
|
||||
if contract_id:
|
||||
contract = self.env['gn_payroll.hr.contract'].browse(contract_id)
|
||||
if contract.parent_contract_id:
|
||||
career.write({'main_contract_id': contract.parent_contract_id.id})
|
||||
return career
|
@ -0,0 +1,59 @@
|
||||
from odoo import models, api
|
||||
from datetime import datetime, time
|
||||
|
||||
class GnPayrollHrPayslip(models.Model):
|
||||
_inherit = 'hr.payslip'
|
||||
|
||||
def _compute_sickness_days(self, contract, day_from, day_to):
|
||||
"""
|
||||
Worked days computation
|
||||
@return: returns a list containing the total worked_days for the period
|
||||
of the payslip. This returns the FULL work days expected for the resource
|
||||
calendar selected for the employee (it don't substract leaves by default).
|
||||
"""
|
||||
work_data = contract.employee_id._get_work_days_data_batch(
|
||||
day_from,
|
||||
day_to,
|
||||
calendar=contract.resource_calendar_id,
|
||||
compute_leaves=False,
|
||||
)
|
||||
return {
|
||||
"name": "Sickness days",
|
||||
"sequence": 1,
|
||||
"code": "SICKNESS",
|
||||
"number_of_days": work_data[contract.employee_id.id]["days"],
|
||||
"number_of_hours": work_data[contract.employee_id.id]["hours"],
|
||||
"contract_id": contract.id,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def get_worked_day_lines(self, contracts, date_from, date_to):
|
||||
"""
|
||||
@param contracts: Browse record of contracts
|
||||
@return: returns a list of dict containing the input that should be
|
||||
applied for the given contract between date_from and date_to
|
||||
"""
|
||||
res = []
|
||||
for contract in contracts.filtered(
|
||||
lambda contract: contract.resource_calendar_id
|
||||
):
|
||||
day_from = datetime.combine(date_from, time.min)
|
||||
day_to = datetime.combine(date_to, time.max)
|
||||
day_contract_start = datetime.combine(contract.date_start, time.min)
|
||||
# Support for the hr_public_holidays module.
|
||||
contract = contract.with_context(
|
||||
employee_id=self.employee_id.id, exclude_public_holidays=True
|
||||
)
|
||||
# only use payslip day_from if it's greather than contract start date
|
||||
if day_from < day_contract_start:
|
||||
day_from = day_contract_start
|
||||
# == compute leave days == #
|
||||
leaves = self._compute_leave_days(contract, day_from, day_to)
|
||||
res.extend(leaves)
|
||||
# == compute worked days == #
|
||||
attendances = self._compute_worked_days(contract, day_from, day_to)
|
||||
res.append(attendances)
|
||||
# == compute sicknss days == #
|
||||
sickness = self._compute_sickness_days(contract, day_from, day_to)
|
||||
res.append(sickness)
|
||||
return res
|
@ -1,3 +1,5 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_gn_payroll_cc_user,gn_payroll_cc_user,model_gn_payroll_cc,base.group_user,1,0,0,0
|
||||
acces_gn_payroll_cc_admin,gn_payroll_cc_admin,model_gn_payroll_cc,hr_contract.group_hr_contract_manager,1,1,0,0
|
||||
access_gn_payroll_hr_contract_entretien_user,gn_payroll_hr_contract_entretien_user,model_gn_payroll_hr_contract_entretien,base.group_user,1,0,0,0
|
||||
access_gn_payroll_hr_contract_entretien_admin,gn_payroll_hr_contract_entretien_admin,model_gn_payroll_hr_contract_entretien,hr_contract.group_hr_contract_manager,1,1,1,1
|
||||
access_gn_payroll_hr_contract_entretien_type_user,gn_payroll_hr_contract_entretien_type_user,model_gn_payroll_hr_contract_entretien_type,base.group_user,1,0,0,0
|
||||
access_gn_payroll_hr_contract_entretien_type_admin,gn_payroll_hr_contract_entretien_type_admin,model_gn_payroll_hr_contract_entretien_type,hr_contract.group_hr_contract_manager,1,1,1,1
|
|
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="gn_view_calendar_event_form" model="ir.ui.view">
|
||||
<field name="name">gncalendar.event.form</field>
|
||||
<field name="model">calendar.event</field>
|
||||
<field name="inherit_id" ref="calendar.view_calendar_event_form"/>
|
||||
<field name="priority" eval="1"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//field[@name='categ_ids']" position="after">
|
||||
<field name="is_entretien"/>
|
||||
<field name="entretien_ids" domain="[('event_id', '=', False)]" attrs="{'invisible': [('is_entretien', '=', False)]}"/>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="gn_payroll_entretien_form_view" model="ir.ui.view">
|
||||
<field name="name">gn_payroll.hr.contract.entretien.form</field>
|
||||
<field name="model">gn_payroll.hr.contract.entretien</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Entretiens">
|
||||
<sheet string="Entretien">
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Entretien" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="ref"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="interviewer_id"/>
|
||||
<field name="other_interviewer_ids"/>
|
||||
<field name="other_participant_ids"/>
|
||||
<field name="event_ids"/>
|
||||
<field name="event_id"/>
|
||||
<field name="start"/>
|
||||
<field name="first_date"/>
|
||||
<field name="next_date"/>
|
||||
<field name="main_contract_id"/>
|
||||
<field name="running_contract_id"/>
|
||||
<field name="generated_contract_id"/>
|
||||
<field name="type_id"/>
|
||||
<field name="report"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="gn_payroll.hr_contract_entretien" model="ir.actions.act_window">
|
||||
<field name="name">Entretiens</field>
|
||||
<field name="res_model">gn_payroll.hr.contract.entretien</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<record id="gn_payroll.hr_contract_entretien_type" model="ir.actions.act_window">
|
||||
<field name="name">Types d'Entretiens</field>
|
||||
<field name="res_model">gn_payroll.hr.contract.entretien.type</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
</odoo>
|
Loading…
Reference in New Issue