mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-26 21:52:02 +02:00
Initial commit: Hr packages
This commit is contained in:
commit
62531cd146
2820 changed files with 1432848 additions and 0 deletions
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import hr_contract_history
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,137 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class ContractHistory(models.Model):
|
||||
_name = 'hr.contract.history'
|
||||
_description = 'Contract history'
|
||||
_auto = False
|
||||
_order = 'is_under_contract'
|
||||
|
||||
# Even though it would have been obvious to use the reference contract's id as the id of the
|
||||
# hr.contract.history model, it turned out it was a bad idea as this id could change (for instance if a
|
||||
# new contract is created with a later start date). The hr.contract.history is instead closely linked
|
||||
# to the employee. That's why we will use this id (employee_id) as the id of the hr.contract.history.
|
||||
contract_id = fields.Many2one('hr.contract', readonly=True)
|
||||
|
||||
display_name = fields.Char(compute='_compute_display_name')
|
||||
name = fields.Char('Contract Name', readonly=True)
|
||||
date_hired = fields.Date('Hire Date', readonly=True)
|
||||
date_start = fields.Date('Start Date', readonly=True)
|
||||
date_end = fields.Date('End Date', readonly=True)
|
||||
employee_id = fields.Many2one('hr.employee', string='Employee', readonly=True)
|
||||
active_employee = fields.Boolean('Active Employee', readonly=True)
|
||||
is_under_contract = fields.Boolean('Is Currently Under Contract', readonly=True)
|
||||
department_id = fields.Many2one('hr.department', string='Department', readonly=True)
|
||||
structure_type_id = fields.Many2one('hr.payroll.structure.type', string='Salary Structure Type', readonly=True)
|
||||
hr_responsible_id = fields.Many2one('res.users', string='HR Responsible', readonly=True)
|
||||
job_id = fields.Many2one('hr.job', string='Job Position', readonly=True)
|
||||
state = fields.Selection([
|
||||
('draft', 'New'),
|
||||
('open', 'Running'),
|
||||
('close', 'Expired'),
|
||||
('cancel', 'Cancelled')
|
||||
], string='Status', readonly=True)
|
||||
resource_calendar_id = fields.Many2one('resource.calendar', string="Working Schedule", readonly=True)
|
||||
wage = fields.Monetary('Wage', help="Employee's monthly gross wage.", readonly=True, group_operator="avg")
|
||||
company_id = fields.Many2one('res.company', string='Company', readonly=True)
|
||||
company_country_id = fields.Many2one('res.country', string="Company country", related='company_id.country_id', readonly=True)
|
||||
country_code = fields.Char(related='company_country_id.code', depends=['company_country_id'], readonly=True)
|
||||
currency_id = fields.Many2one(string='Currency', related='company_id.currency_id', readonly=True)
|
||||
contract_type_id = fields.Many2one('hr.contract.type', 'Contract Type', readonly=True)
|
||||
contract_ids = fields.One2many('hr.contract', string='Contracts', compute='_compute_contract_ids', readonly=True, compute_sudo=True)
|
||||
contract_count = fields.Integer(compute='_compute_contract_count', string="# Contracts")
|
||||
under_contract_state = fields.Selection([
|
||||
('done', 'Under Contract'),
|
||||
('blocked', 'Not Under Contract')
|
||||
], string='Contractual Status', compute='_compute_under_contract_state')
|
||||
activity_state = fields.Selection(related='contract_id.activity_state')
|
||||
|
||||
@api.depends('contract_ids')
|
||||
def _compute_contract_count(self):
|
||||
for history in self:
|
||||
history.contract_count = len(history.contract_ids)
|
||||
|
||||
@api.depends('is_under_contract')
|
||||
def _compute_under_contract_state(self):
|
||||
for history in self:
|
||||
history.under_contract_state = 'done' if history.is_under_contract else 'blocked'
|
||||
|
||||
@api.depends('employee_id.name')
|
||||
def _compute_display_name(self):
|
||||
for history in self:
|
||||
history.display_name = _("%s's Contracts History", history.employee_id.name)
|
||||
|
||||
@api.model
|
||||
def _get_fields(self):
|
||||
return ','.join('contract.%s' % name for name, field in self._fields.items()
|
||||
if field.store
|
||||
and field.type not in ['many2many', 'one2many', 'related']
|
||||
and field.name not in ['id', 'contract_id', 'employee_id', 'date_hired', 'is_under_contract', 'active_employee'])
|
||||
|
||||
def init(self):
|
||||
tools.drop_view_if_exists(self.env.cr, self._table)
|
||||
# Reference contract is the one with the latest start_date.
|
||||
self.env.cr.execute("""CREATE or REPLACE VIEW %s AS (
|
||||
WITH contract_information AS (
|
||||
SELECT DISTINCT employee_id,
|
||||
company_id,
|
||||
FIRST_VALUE(id) OVER w_partition AS id,
|
||||
MAX(CASE
|
||||
WHEN state='open' THEN 1
|
||||
WHEN state='draft' AND kanban_state='done' THEN 1
|
||||
ELSE 0 END) OVER w_partition AS is_under_contract
|
||||
FROM hr_contract AS contract
|
||||
WHERE contract.active = true
|
||||
WINDOW w_partition AS (
|
||||
PARTITION BY contract.employee_id, contract.company_id
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN contract.state = 'open' THEN 0
|
||||
WHEN contract.state = 'draft' THEN 1
|
||||
WHEN contract.state = 'close' THEN 2
|
||||
WHEN contract.state = 'cancel' THEN 3
|
||||
ELSE 4 END,
|
||||
contract.date_start DESC
|
||||
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
|
||||
)
|
||||
)
|
||||
SELECT DISTINCT employee.id AS id,
|
||||
employee.id AS employee_id,
|
||||
employee.active AS active_employee,
|
||||
contract.id AS contract_id,
|
||||
contract_information.is_under_contract::bool AS is_under_contract,
|
||||
employee.first_contract_date AS date_hired,
|
||||
%s
|
||||
FROM hr_contract AS contract
|
||||
INNER JOIN contract_information ON contract.id = contract_information.id
|
||||
RIGHT JOIN hr_employee AS employee
|
||||
ON contract_information.employee_id = employee.id
|
||||
AND contract.company_id = employee.company_id
|
||||
WHERE employee.employee_type IN ('employee', 'student', 'trainee')
|
||||
)""" % (self._table, self._get_fields()))
|
||||
|
||||
@api.depends('employee_id.contract_ids')
|
||||
def _compute_contract_ids(self):
|
||||
sorted_contracts = self.mapped('employee_id.contract_ids').sorted('date_start', reverse=True)
|
||||
|
||||
mapped_employee_contracts = defaultdict(lambda: self.env['hr.contract'])
|
||||
for contract in sorted_contracts:
|
||||
mapped_employee_contracts[contract.employee_id] |= contract
|
||||
|
||||
for history in self:
|
||||
history.contract_ids = mapped_employee_contracts[history.employee_id]
|
||||
|
||||
def hr_contract_view_form_new_action(self):
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.actions']._for_xml_id('hr_contract.action_hr_contract')
|
||||
action.update({
|
||||
'context': {'default_employee_id': self.employee_id.id},
|
||||
'view_mode': 'form',
|
||||
'view_id': self.env.ref('hr_contract.hr_contract_view_form').id,
|
||||
'views': [(self.env.ref('hr_contract.hr_contract_view_form').id, 'form')],
|
||||
})
|
||||
return action
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="hr_contract_history_view_search" model="ir.ui.view">
|
||||
<field name="name">hr.contract.history.search</field>
|
||||
<field name="model">hr.contract.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Reference Contracts">
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="job_id"/>
|
||||
<field name="department_id" operator="child_of"/>
|
||||
<field name="resource_calendar_id"/>
|
||||
<field name="state"/>
|
||||
<field name="is_under_contract"/>
|
||||
<filter string="Running Contracts" name="open_contracts" domain="[('state', '=', 'open')]"/>
|
||||
<filter string="Contracts to Review" name="contract_to_review" domain="['|', ('state', 'in', ['draft', 'close', 'cancel']), ('is_under_contract', '!=', True)]"/>
|
||||
<filter string="No Contracts" name="no_contracts" domain="[('contract_id', '=', False)]"/>
|
||||
<filter string="Currently Under Contract" name="currently_under_contract" domain="[('is_under_contract', '=', True)]"/>
|
||||
<filter string="Active Employees" name="active_employees" domain="[('active_employee', '=', True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Job Position" name="job" domain="[]" context="{'group_by': 'job_id'}"/>
|
||||
<filter string="Status" name='group_by_state' domain="[]" context="{'group_by': 'state'}"/>
|
||||
<filter string="Reference Working Time" name="group_by_resource_calendar_id" domain="[]" context="{'group_by': 'resource_calendar_id'}"/>
|
||||
<filter string="Salary Structure Type" name="group_by_structure_type_id" domain="[]" context="{'group_by': 'structure_type_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_view_form_action" model="ir.actions.act_window">
|
||||
<field name="name">Contracts</field>
|
||||
<field name="res_model">hr.contract.history</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="context">{'search_default_active_employees': 1}</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_view_form" model="ir.ui.view">
|
||||
<field name="name">hr.contract.history.form</field>
|
||||
<field name="model">hr.contract.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Contract History"
|
||||
create="false"
|
||||
edit="false"
|
||||
delete="false"
|
||||
duplicate="false"
|
||||
import="false">
|
||||
<header>
|
||||
<button name="hr_contract_view_form_new_action" string="Create" type="object" groups="hr_contract.group_hr_contract_manager" class="btn-primary"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box"/>
|
||||
<h1>
|
||||
<div class="d-flex justify-content-start">
|
||||
<div>
|
||||
<field name="display_name"/>
|
||||
</div>
|
||||
<div class="ps-3">
|
||||
<field name="under_contract_state" widget="state_selection" readonly="1"/>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
<h2>
|
||||
<field name="employee_id"/>
|
||||
</h2>
|
||||
<group>
|
||||
<group>
|
||||
<field name="contract_id" invisible="1"/>
|
||||
<field name="company_country_id" invisible="1"/>
|
||||
<field name="country_code" invisible="1"/>
|
||||
<field name="structure_type_id"/>
|
||||
<field name="resource_calendar_id"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="wage" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="department_id"/>
|
||||
<field name="job_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Contract History" name="contract_history">
|
||||
<field name="contract_ids" widget="one2many" readonly="0">
|
||||
<tree string="Current Contracts"
|
||||
decoration-primary="state == 'open'"
|
||||
decoration-muted="state == 'close'"
|
||||
decoration-bf="id == parent.contract_id"
|
||||
default_order = "date_start desc, state desc"
|
||||
editable="bottom"
|
||||
no_open="1"
|
||||
create="0" delete="0">
|
||||
<button name="action_open_contract_form" type="object" icon="fa-external-link" title="Open Contract"/>
|
||||
<field name="id" invisible="1"/>
|
||||
<field name="name" string="Contract Name"/>
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="resource_calendar_id"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="wage" string="Monthly Wage"/>
|
||||
<field name="state" widget="badge" decoration-info="state == 'draft'" decoration-warning="state == 'close'" decoration-success="state == 'open'"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Employee Information" name="contract_others">
|
||||
<group>
|
||||
<field name="date_hired"/>
|
||||
<field name="hr_responsible_id"/>
|
||||
<field name="company_id"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_view_list_action" model="ir.actions.act_window">
|
||||
<field name="name">Employees</field>
|
||||
<field name="res_model">hr.contract.history</field>
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
<field name="search_view_id" ref="hr_contract_history_view_search"/>
|
||||
<field name="context">
|
||||
{
|
||||
'search_default_active_employees': 1,
|
||||
'search_default_group_by_state': 1
|
||||
}
|
||||
</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_empty_folder">
|
||||
No data to display
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_to_review_view_list_action" model="ir.actions.act_window">
|
||||
<field name="name">Contracts to Review</field>
|
||||
<field name="res_model">hr.contract.history</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="hr_contract_history_view_search"/>
|
||||
<field name="context">
|
||||
{
|
||||
'search_default_to_review': 1,
|
||||
'search_default_active_employees': 1
|
||||
}
|
||||
</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_view_list" model="ir.ui.view">
|
||||
<field name="name">hr.contract.history.list</field>
|
||||
<field name="model">hr.contract.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Contracts"
|
||||
js_class="hr_contract_history_list"
|
||||
default_order = 'is_under_contract, date_start desc'
|
||||
edit="false"
|
||||
delete="false"
|
||||
duplicate="false"
|
||||
import="false"
|
||||
create="false">
|
||||
<field name="employee_id" widget="many2one_avatar_employee"/>
|
||||
<field name="date_hired"/>
|
||||
<field name="is_under_contract" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date_start"/>
|
||||
<field string="Reference Working Time" name="resource_calendar_id" optional="hide"/>
|
||||
<field name="under_contract_state" widget="state_selection" optional="hide"/>
|
||||
<field name="structure_type_id" optional="hide"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="wage" optional="hide"/>
|
||||
<field name="state"
|
||||
widget="badge"
|
||||
decoration-info="state == 'draft'"
|
||||
decoration-warning="state == 'close'"
|
||||
decoration-success="state == 'open'"/>
|
||||
<field name="contract_count"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="hr_contract_history_view_kanban" model="ir.ui.view">
|
||||
<field name="name">hr.contract.history.view.kanban</field>
|
||||
<field name="model">hr.contract.history</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_small_column" default_order="date_end" sample="1" create="0">
|
||||
<field name="employee_id"/>
|
||||
<field name="activity_state"/>
|
||||
<field name="state"/>
|
||||
<progressbar field="activity_state" colors='{"planned": "success", "today": "warning", "overdue": "danger"}'/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_card oe_kanban_global_click">
|
||||
<div class="oe_kanban_content">
|
||||
<div class="o_hr_contract_state">
|
||||
<strong class="o_kanban_record_title">
|
||||
<field name="display_name"/>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="text-muted o_kanban_record_subtitle o_hr_contract_job_id">
|
||||
<field name="job_id"/>
|
||||
</div>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<span class="float-end">
|
||||
<field name="employee_id" widget="many2one_avatar_employee"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="hr_menu_contract_history"
|
||||
action="hr_contract_history_view_list_action"
|
||||
parent="hr.menu_hr_employee_payroll"
|
||||
name="Contracts"
|
||||
sequence="4"
|
||||
groups="hr_contract.group_hr_contract_manager"/>
|
||||
</odoo>
|
||||
Loading…
Add table
Add a link
Reference in a new issue