Compare commits
22 Commits
old16.0
...
16-payroll
Author | SHA1 | Date |
---|---|---|
Florian Roger | bc4049e1e4 | 7 months ago |
Florian Roger | 89534a647c | 7 months ago |
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 Avenants
|
||||
|
||||
Module de gestion des avenants aux contrats
|
||||
|
||||
## 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/02):
|
||||
- Création du module
|
||||
|
||||
|
||||
## Issues
|
||||
- [] Needs a View for Previous contract (cf issue #9)
|
||||
- [] Needs an Action to Create a New Contract linked with a Previous one (cf issue #10)
|
@ -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,17 @@
|
||||
{
|
||||
"name": "Gestion des Contrats: Typologie et Gestion des Avenants",
|
||||
"version": "16.0.0.0.1",
|
||||
"category": "HR",
|
||||
"summary": "Permet de relier entre eux les contrats",
|
||||
"author": "Le Garage Numérique",
|
||||
"maintainers": ["makayabou"],
|
||||
"website": "https://odoo.legaragenumerique.fr",
|
||||
"depends": [
|
||||
"hr",
|
||||
"hr_contract",
|
||||
],
|
||||
"data": [
|
||||
"data/gn_contract.xml",
|
||||
],
|
||||
"license": "LGPL-3",
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<delete model="hr.payroll.structure.type" id="hr_contract.structure_type_employee"/>
|
||||
<delete model="hr.payroll.structure.type" id="hr_contract.structure_type_worker"/>
|
||||
<record id="gn_contract_structure_type_employe" model="hr.payroll.structure.type">
|
||||
<field name="name">Employé(e)</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_contract_structure_type_cadre" model="hr.payroll.structure.type">
|
||||
<field name="name">Cadre</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_contract_structure_type_service_civique" model="hr.payroll.structure.type">
|
||||
<field name="name">Volontaire en Service civique</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_contract_structure_type_intern" model="hr.payroll.structure.type">
|
||||
<field name="name">Stagiaire</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_contract_structure_type_benevolent" model="hr.payroll.structure.type">
|
||||
<field name="name">Administrateur(-trice) bénévole</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_contract_contract_cae" model="hr.contract.type">
|
||||
<field name="name">PEC - CAE</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_apprentissage" model="hr.contract.type">
|
||||
<field name="name">Contrat d'apprentissage</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_cdd" model="hr.contract.type">
|
||||
<field name="name">CDD</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_cdi" model="hr.contract.type">
|
||||
<field name="name">CDI</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_service_civique" model="hr.contract.type">
|
||||
<field name="name">Service civique</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_admin" model="hr.contract.type">
|
||||
<field name="name">Administrateur bénévole</field>
|
||||
</record>
|
||||
<record id="gn_contract_contract_internship" model="hr.contract.type">
|
||||
<field name="name">Stage</field>
|
||||
</record>
|
||||
</odoo>
|
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import gn_contract
|
||||
from . import gn_employee
|
@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, api
|
||||
|
||||
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)")
|
||||
lineage_sequence_number = fields.Integer(string="Numéro de séquence dans l'historique du salarié", default=0)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
contract = super(GnHrContract, self).create(vals)
|
||||
if contract.previous_contract_id:
|
||||
previous_number = contract.previous_contract_id.lineage_sequence_number
|
||||
contract.lineage_sequence_number = previous_number + 1
|
||||
return contract
|
@ -0,0 +1,28 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
class GnHrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
employee_type = fields.Selection([
|
||||
('employee', 'Employé'),
|
||||
('student', 'Étudiant'),
|
||||
('trainee', 'Stagiaire'),
|
||||
('volunteer', 'Volontaire'),
|
||||
('benevolent', 'Bénévole'),
|
||||
], string='Employee Type', default='employee', required=True,
|
||||
help="The employee type. Although the primary purpose may seem to categorize employees, this field has also an impact in the Contract History. Only Employee type is supposed to be under contract and will have a Contract History.")
|
||||
|
||||
anciennete_start_date = fields.Date(compute='_compute_anciennete_start_date', groups='hr_group.hr_user', store=True)
|
||||
|
||||
@api.depends('contract_ids.state', 'contract_ids.date_start')
|
||||
def _compute_anciennete_start_date(self):
|
||||
for employee in self:
|
||||
if employee.contract_id:
|
||||
contract = employee.contract_id
|
||||
|
||||
while contract.previous_contract_id:
|
||||
contract = contract.previous_contract_id
|
||||
|
||||
employee.anciennete_start_date = previous_contract.date_start
|
||||
|
||||
else:
|
||||
employee.anciennete_start_date = False
|
@ -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>
|
@ -1,46 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<delete model="hr.payroll.structure.type" id="hr_contract.structure_type_employee"/>
|
||||
<delete model="hr.payroll.structure.type" id="hr_contract.structure_type_worker"/>
|
||||
<record id="gn_payroll_structure_type_employe" model="hr.payroll.structure.type">
|
||||
<field name="name">Employé(e)</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_payroll_structure_type_cadre" model="hr.payroll.structure.type">
|
||||
<field name="name">Cadre</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_payroll_structure_type_service_civique" model="hr.payroll.structure.type">
|
||||
<field name="name">Volontaire en Service civique</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_payroll_structure_type_intern" model="hr.payroll.structure.type">
|
||||
<field name="name">Stagiaire</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="payroll_structure_type_benevolent" model="hr.payroll.structure.type">
|
||||
<field name="name">Administrateur bénévole</field>
|
||||
<field name="country_id" eval="False"/>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_cae" model="hr.contract.type">
|
||||
<field name="name">PEC - CAE</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_apprentissage" model="hr.contract.type">
|
||||
<field name="name">Contrat d'apprentissage</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_cdd" model="hr.contract.type">
|
||||
<field name="name">CDD</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_cdi" model="hr.contract.type">
|
||||
<field name="name">CDI</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_service_civique" model="hr.contract.type">
|
||||
<field name="name">Service civique</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_admin" model="hr.contract.type">
|
||||
<field name="name">Administrateur bénévole</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_internship" model="hr.contract.type">
|
||||
<field name="name">Stage</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_annuel" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien annuel d'évaluation</field>
|
||||
<field name="month_delay">12</field>
|
||||
<field name="start_point">endofyear</field>
|
||||
<field name="auto">True</field>
|
||||
<field name="cc_ids" eval="[(6, 0, [ref('gn_payroll.cc_3442')])]"></field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_periodique" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien professionnel périodique</field>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_periodique_retour" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien professionnel périodique de retour de congé long</field>
|
||||
<field name="parent_id" ref="gn_payroll_contract_entretien_type_periodique"/>
|
||||
<field name="month_delay">0</field>
|
||||
<field name="cc_ids" eval="[(6, 0, [ref('gn_payroll.cc_3442')])]"/>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_periodique_initial" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien professionnel périodique des 2 ans</field>
|
||||
<field name="parent_id" ref="gn_payroll_contract_entretien_type_periodique"/>
|
||||
<field name="start_point">contract</field>
|
||||
<field name="month_delay">24</field>
|
||||
<field name="auto">True</field>
|
||||
<field name="cc_ids" eval="[(6, 0, [ref('gn_payroll.cc_3442')])]"/>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_periodique_bilan" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien professionnel bilan des 6 ans</field>
|
||||
<field name="parent_id" ref="gn_payroll_contract_entretien_type_periodique"/>
|
||||
<field name="start_point">contract</field>
|
||||
<field name="month_delay">72</field>
|
||||
<field name="auto">True</field>
|
||||
<field name="cc_ids" eval="[(6, 0, [ref('gn_payroll.cc_3442')])]"/>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_valorisation" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Entretien de valorisation des acquis professionnels</field>
|
||||
<field name="start_point">contract</field>
|
||||
<field name="month_delay">48</field>
|
||||
<field name="generate_subcontract" eval="True"/>
|
||||
<field name="auto">True</field>
|
||||
<field name="cc_ids" eval="[(6, 0, [ref('gn_payroll.cc_3442')])]"/>
|
||||
</record>
|
||||
<record id="gn_payroll_contract_entretien_type_modif_cc" model="gn_payroll.hr.contract.entretien.type">
|
||||
<field name="name">Modification conventionnelle</field>
|
||||
</record>
|
||||
<data noupdate="1">
|
||||
<!-- Define the sequence for the Entretien model -->
|
||||
<record id="seq_entretien" model="ir.sequence">
|
||||
<field name="name">Entretien Sequence</field>
|
||||
<field name="code">gn_payroll.hr.contract.entretien</field>
|
||||
<field name="prefix">ENT</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
</data>
|
||||
<menuitem
|
||||
id="menu_human_resources_configuration_contract_entretien"
|
||||
name="Entretiens"
|
||||
parent="hr.menu_hr_employee_payroll"
|
||||
sequence="35"
|
||||
action="gn_payroll.hr_contract_entretien"
|
||||
groups="hr.group_hr_manager"/>
|
||||
</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
|
@ -1,12 +1,17 @@
|
||||
from odoo import models, fields
|
||||
from odoo import models, fields, api
|
||||
|
||||
class GnPayrollHrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
employee_type = fields.Selection([
|
||||
('employee', 'Employé'),
|
||||
('student', 'Étudiant'),
|
||||
('trainee', 'Stagiaire'),
|
||||
('volunteer', 'Volontaire'),
|
||||
('benevolent', 'Bénévole'),
|
||||
], string='Employee Type', default='employee', required=True,
|
||||
help="The employee type. Although the primary purpose may seem to categorize employees, this field has also an impact in the Contract History. Only Employee type is supposed to be under contract and will have a Contract History.")
|
||||
|
||||
anciennete_start_date = fields.Date(compute='_compute_anciennete_start_date', groups='hr_group.hr_user', store=True)
|
||||
|
||||
@api.depends('contract_ids.state', 'contract_ids.date_start')
|
||||
def _compute_anciennete_start_date(self):
|
||||
for employee in self:
|
||||
if employee.contract_id:
|
||||
if employee.contract_id.parent_contract_id:
|
||||
employee.anciennete_start_date = employee.contract_id.parent_contract_id.date_start
|
||||
else:
|
||||
employee.anciennete_start_date = employee.contract_id.date_start
|
||||
else:
|
||||
employee.anciennete_start_date = False
|
@ -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