summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorKevin Baptiste <kba@odoo.com>2019-05-16 13:30:01 +0000
committerYannick Tivisse <yti@odoo.com>2019-06-28 06:59:32 +0000
commitf17655dd773096f2d37ece392dfe980ae4795819 (patch)
tree13045498b08d8975d3155c72c34bd347e2280676 /addons
parent5548029fb73c420a308772e9c54b8119775105b7 (diff)
[IMP] hr_contract: Replace some contract states by kanban status
Purpose ======= Having some usability check to be sure to make the pay for everyone, and don't loose contracts. We would like to remove incoming and to renew columns in hr.contract and replace them by a kanban state. In employee, we would like to add warning on the kanban to warn the hr responsible there is no contract or a contract is about to expire Specification ============= hr.contract kanban: - add a kanabn state - it becomes red automatically when the contract is in running and expire in 7 days - add aquick search in filter to filter on expered soon - the kanban state can be changed manaually (in case of there is several rh) - sort by contract end date set first (more close of today first) Employee kanban - add an red icon if there is no contract in Runnig status OR there is a kanban state red in their contract (whatever the status). - add a quick seaach on employee with warning - State pending + green = incoming - State confirmed + red = about to expire / to renew closes odoo/odoo#33489 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/hr_contract/__manifest__.py2
-rw-r--r--addons/hr_contract/data/hr_contract_demo.xml15
-rw-r--r--addons/hr_contract/models/hr_contract.py71
-rw-r--r--addons/hr_contract/models/hr_employee.py32
-rw-r--r--addons/hr_contract/static/src/scss/state_selection.scss9
-rw-r--r--addons/hr_contract/tests/test_auto_status.py19
-rw-r--r--addons/hr_contract/tests/test_contract.py29
-rw-r--r--addons/hr_contract/views/assets.xml7
-rw-r--r--addons/hr_contract/views/hr_contract_views.xml58
9 files changed, 180 insertions, 62 deletions
diff --git a/addons/hr_contract/__manifest__.py b/addons/hr_contract/__manifest__.py
index d229c773b53..f05b650c937 100644
--- a/addons/hr_contract/__manifest__.py
+++ b/addons/hr_contract/__manifest__.py
@@ -23,7 +23,7 @@ You can assign several contracts per employee.
'security/ir.model.access.csv',
'data/hr_contract_data.xml',
'views/hr_contract_views.xml',
- 'views/hr_contract_templates.xml',
+ 'views/assets.xml',
],
'demo': ['data/hr_contract_demo.xml'],
'installable': True,
diff --git a/addons/hr_contract/data/hr_contract_demo.xml b/addons/hr_contract/data/hr_contract_demo.xml
index c7092205f57..591137f2f88 100644
--- a/addons/hr_contract/data/hr_contract_demo.xml
+++ b/addons/hr_contract/data/hr_contract_demo.xml
@@ -11,6 +11,7 @@
eval="obj().env.ref('hr.employee_admin').department_id.id"/>
<field eval="7540.0" name="wage"/>
<field name="state">draft</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_al" model="hr.contract">
@@ -23,6 +24,7 @@
eval="obj().env.ref('hr.employee_al').department_id.id"/>
<field eval="4000.0" name="wage"/>
<field name="state">open</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_mit" model="hr.contract">
@@ -35,6 +37,7 @@
eval="obj().env.ref('hr.employee_mit').department_id.id"/>
<field eval="4500.0" name="wage"/>
<field name="state">open</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_stw" model="hr.contract">
@@ -48,6 +51,7 @@
eval="obj().env.ref('hr.employee_stw').department_id.id"/>
<field eval="4500.0" name="wage"/>
<field name="state">open</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_qdp" model="hr.contract">
@@ -60,6 +64,7 @@
eval="obj().env.ref('hr.employee_qdp').department_id.id"/>
<field eval="3750.0" name="wage"/>
<field name="state">draft</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_han" model="hr.contract">
@@ -72,6 +77,7 @@
eval="obj().env.ref('hr.employee_han').department_id.id"/>
<field eval="4600.0" name="wage"/>
<field name="state">open</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_niv" model="hr.contract">
@@ -85,6 +91,7 @@
eval="obj().env.ref('hr.employee_niv').department_id.id"/>
<field eval="4000.0" name="wage"/>
<field name="state">draft</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_jth" model="hr.contract">
@@ -98,6 +105,7 @@
eval="obj().env.ref('hr.employee_jth').department_id.id"/>
<field eval="4200.0" name="wage"/>
<field name="state">draft</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_chs" model="hr.contract">
@@ -110,6 +118,7 @@
eval="obj().env.ref('hr.employee_chs').department_id.id"/>
<field eval="3750.0" name="wage"/>
<field name="state">cancel</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_jve" model="hr.contract">
@@ -122,6 +131,7 @@
eval="obj().env.ref('hr.employee_jve').department_id.id"/>
<field eval="3950.0" name="wage"/>
<field name="state">cancel</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_fme" model="hr.contract">
@@ -134,7 +144,8 @@
<field name="department_id" model="hr.department"
eval="obj().env.ref('hr.employee_fme').department_id.id"/>
<field eval="3650.0" name="wage"/>
- <field name="state">pending</field>
+ <field name="state">open</field>
+ <field name="kanban_state">blocked</field>
</record>
<record id="hr_contract_fpi" model="hr.contract">
@@ -148,6 +159,7 @@
eval="obj().env.ref('hr.employee_fpi').department_id.id"/>
<field eval="3750.0" name="wage"/>
<field name="state">close</field>
+ <field name="kanban_state">normal</field>
</record>
<record id="hr_contract_vad" model="hr.contract">
@@ -161,6 +173,7 @@
eval="obj().env.ref('hr.employee_vad').department_id.id"/>
<field eval="3750.0" name="wage"/>
<field name="state">close</field>
+ <field name="kanban_state">normal</field>
</record>
</odoo> \ No newline at end of file
diff --git a/addons/hr_contract/models/hr_contract.py b/addons/hr_contract/models/hr_contract.py
index 544ec534715..343479f3bdb 100644
--- a/addons/hr_contract/models/hr_contract.py
+++ b/addons/hr_contract/models/hr_contract.py
@@ -6,8 +6,8 @@ from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
-from odoo.osv import expression
+from odoo.osv import expression
class Contract(models.Model):
_name = 'hr.contract'
@@ -33,14 +33,23 @@ class Contract(models.Model):
notes = fields.Text('Notes')
state = fields.Selection([
('draft', 'New'),
- ('incoming', 'Incoming'),
('open', 'Running'),
- ('pending', 'To Renew'),
('close', 'Expired'),
('cancel', 'Cancelled')
], string='Status', group_expand='_expand_states',
tracking=True, help='Status of the contract', default='draft')
company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
+ """
+ kanban_state:
+ * draft + green = "Incoming" state (will be set as Open once the contract has started)
+ * open + red = "Pending" state (will be set as Closed once the contract has ended)
+ * red = Shows a warning on the employees kanban view
+ """
+ kanban_state = fields.Selection([
+ ('normal', 'Grey'),
+ ('done', 'Green'),
+ ('blocked', 'Red')
+ ], string='Kanban State', default='normal', tracking=True)
currency_id = fields.Many2one(string="Currency", related='company_id.currency_id', readonly=True)
permit_no = fields.Char('Work Permit No', related="employee_id.permit_no", readonly=False)
visa_no = fields.Char('Visa No', related="employee_id.visa_no", readonly=False)
@@ -57,6 +66,7 @@ class Contract(models.Model):
def _expand_states(self, states, domain, order):
return [key for key, val in type(self).state.selection]
+
@api.onchange('employee_id')
def _onchange_employee_id(self):
if self.employee_id:
@@ -64,14 +74,18 @@ class Contract(models.Model):
self.department_id = self.employee_id.department_id
self.resource_calendar_id = self.employee_id.resource_calendar_id
- @api.constrains('employee_id', 'state', 'date_start', 'date_end')
+ @api.constrains('employee_id', 'state', 'kanban_state', 'date_start', 'date_end')
def _check_current_contract(self):
- """ Two contracts in state [incoming | pending | open] cannot overlap """
- for contract in self.filtered(lambda c: c.state not in ['draft', 'cancel', 'close']):
+ """ Two contracts in state [incoming | open | close] cannot overlap """
+ for contract in self.filtered(lambda c: c.state not in ['draft', 'cancel'] or c.state == 'draft' and c.kanban_state == 'done'):
domain = [
('id', '!=', contract.id),
('employee_id', '=', contract.employee_id.id),
- ('state', 'in', ['incoming', 'pending', 'open']),
+ '|',
+ ('state', 'in', ['open', 'close']),
+ '&',
+ ('state', '=', 'draft'),
+ ('kanban_state', '=', 'done') # replaces incoming
]
if not contract.date_end:
@@ -102,11 +116,11 @@ class Contract(models.Model):
('visa_expire', '<=', fields.Date.to_string(date.today() + relativedelta(days=60))),
('visa_expire', '>=', fields.Date.to_string(date.today() + relativedelta(days=1))),
]).write({
- 'state': 'pending'
+ 'kanban_state': 'blocked'
})
self.search([
- ('state', 'in', ('open', 'pending')),
+ ('state', '=', 'open'),
'|',
('date_end', '<=', fields.Date.to_string(date.today() + relativedelta(days=1))),
('visa_expire', '<=', fields.Date.to_string(date.today() + relativedelta(days=1))),
@@ -114,38 +128,45 @@ class Contract(models.Model):
'state': 'close'
})
- self.search([('state', '=', 'incoming'), ('date_start', '<=', fields.Date.to_string(date.today())),]).write({
+ self.search([('state', '=', 'draft'), ('kanban_state', '=', 'done'), ('date_start', '<=', fields.Date.to_string(date.today())),]).write({
'state': 'open'
})
return True
- @api.model
- def create(self, vals_list):
- contracts = super().create(vals_list)
- open_contracts = contracts.filtered(lambda c: c.state in ['open', 'pending'])
- # sync contract -> employee
- for contract in open_contracts:
- contract.employee_id.contract_id = contract
- # sync contract calendar -> calendar employee
- for contract in open_contracts.filtered(lambda c: c.resource_calendar_id):
- contract.employee_id.resource_calendar_id = contract.resource_calendar_id
- return contracts
+ def _assign_open_contract(self):
+ for contract in self:
+ contract.employee_id.sudo().write({'contract_id': contract.id})
@api.multi
def write(self, vals):
res = super(Contract, self).write(vals)
if vals.get('state') == 'open':
- for contract in self:
- contract.employee_id.sudo().write({'contract_id': contract.id})
+ self._assign_open_contract()
+
calendar = vals.get('resource_calendar_id')
- if calendar and self.state in ['open', 'pending']:
+ if calendar and (self.state == 'open' or (self.state == 'draft' and self.kanban_state == 'done')):
self.mapped('employee_id').write({'resource_calendar_id': calendar})
+
+ if 'state' in vals and 'kanban_state' not in vals:
+ self.write({'kanban_state': 'normal'})
+
return res
+ @api.model
+ def create(self, vals):
+ contracts = super(Contract, self).create(vals)
+ if vals.get('state') == 'open':
+ contracts._assign_open_contract()
+ open_contracts = contracts.filtered(lambda c: c.state == 'open' or c.state == 'draft' and c.kanban_state == 'done')
+ # sync contract calendar -> calendar employee
+ for contract in open_contracts.filtered(lambda c: c.resource_calendar_id):
+ contract.employee_id.resource_calendar_id = contract.resource_calendar_id
+ return contracts
+
@api.multi
def _track_subtype(self, init_values):
self.ensure_one()
- if 'state' in init_values and self.state == 'pending':
+ if 'state' in init_values and self.state == 'open' and 'kanban_state' in init_values and self.kanban_state == 'blocked':
return self.env.ref('hr_contract.mt_contract_pending')
elif 'state' in init_values and self.state == 'close':
return self.env.ref('hr_contract.mt_contract_close')
diff --git a/addons/hr_contract/models/hr_employee.py b/addons/hr_contract/models/hr_employee.py
index 4d596f046e0..a1f36d333b7 100644
--- a/addons/hr_contract/models/hr_employee.py
+++ b/addons/hr_contract/models/hr_employee.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
+from odoo.osv import expression
class Employee(models.Model):
@@ -14,6 +15,12 @@ class Employee(models.Model):
groups="hr.group_hr_user", help='Current contract of the employee')
calendar_mismatch = fields.Boolean(related='contract_id.calendar_mismatch')
contracts_count = fields.Integer(compute='_compute_contracts_count', string='Contract Count')
+ contract_warning = fields.Boolean(string='Contract Warning', store=True, compute='_compute_contract_warning', groups="hr.group_hr_user")
+
+ @api.depends('contract_id', 'contract_id.state', 'contract_id.kanban_state')
+ def _compute_contract_warning(self):
+ for employee in self:
+ employee.contract_warning = not employee.contract_id or employee.contract_id.kanban_state == 'blocked' or employee.contract_id.state != 'open'
def _compute_contracts_count(self):
# read_group as sudo, since contract count is displayed on form view
@@ -22,20 +29,27 @@ class Employee(models.Model):
for employee in self:
employee.contracts_count = result.get(employee.id, 0)
- def _get_contracts(self, date_from, date_to, states=['open', 'pending']):
+ def _get_contracts(self, date_from, date_to, states=['open'], kanban_state=False):
"""
Returns the contracts of the employee between date_from and date_to
"""
- return self.env['hr.contract'].search([
- '&', '&', '&',
- ('employee_id', 'in', self.ids),
- ('state', 'in', states),
- ('date_start', '<=', date_to),
- '|', ('date_end', '=', False), ('date_end', '>=', date_from)
- ])
+ state_domain = [('state', 'in', states)]
+ if kanban_state:
+ state_domain = expression.AND([state_domain, [('kanban_state', 'in', kanban_state)]])
+
+ return self.env['hr.contract'].search(
+ expression.AND([[('employee_id', 'in', self.ids)],
+ state_domain,
+ [('date_start', '<=', date_to),
+ '|',
+ ('date_end', '=', False),
+ ('date_end', '>=', date_from)]]))
+
+ def _get_incoming_contracts(self, date_from, date_to):
+ return self._get_contracts(date_from, date_to, states=['draft'], kanban_state=['done'])
@api.model
- def _get_all_contracts(self, date_from, date_to, states=['open', 'pending']):
+ def _get_all_contracts(self, date_from, date_to, states=['open']):
"""
Returns the contracts of all employees between date_from and date_to
"""
diff --git a/addons/hr_contract/static/src/scss/state_selection.scss b/addons/hr_contract/static/src/scss/state_selection.scss
new file mode 100644
index 00000000000..329cfd28feb
--- /dev/null
+++ b/addons/hr_contract/static/src/scss/state_selection.scss
@@ -0,0 +1,9 @@
+.o_hr_contract_state {
+ .o_status {
+ vertical-align: unset !important;
+ }
+}
+
+.o_hr_contract_job_id {
+ min-height: 1.5rem;
+} \ No newline at end of file
diff --git a/addons/hr_contract/tests/test_auto_status.py b/addons/hr_contract/tests/test_auto_status.py
index c342d05dd0f..fcff8621bb9 100644
--- a/addons/hr_contract/tests/test_auto_status.py
+++ b/addons/hr_contract/tests/test_auto_status.py
@@ -12,6 +12,9 @@ class TestHrContracts(TestContractBase):
self.contracts = self.env['hr.contract'].with_context(tracking_disable=True)
self.test_contract = dict(name='Test', wage=1, employee_id=self.employee.id, state='open')
+ def test_employee_contractwarning(self):
+ self.assertEquals(self.employee.contract_warning, True)
+
def apply_cron(self):
self.env.ref('hr_contract.ir_cron_data_contract_update_state').method_direct_trigger()
@@ -20,16 +23,20 @@ class TestHrContracts(TestContractBase):
self.contract = self.contracts.create(self.test_contract)
self.apply_cron()
self.assertEquals(self.contract.state, 'open')
+ self.assertEquals(self.contract.kanban_state, 'normal')
+ self.assertEquals(self.employee.contract_warning, False)
self.test_contract.update(dict(date_end=datetime.now() + relativedelta(days=5)))
self.contract.write(self.test_contract)
self.apply_cron()
- self.assertEquals(self.contract.state, 'pending')
+ self.assertEquals(self.contract.state, 'open')
+ self.assertEquals(self.contract.kanban_state, 'blocked')
self.test_contract.update({
'date_start': datetime.now() + relativedelta(days=-50),
'date_end': datetime.now() + relativedelta(days=-1),
- 'state': 'pending',
+ 'state': 'open',
+ 'kanban_state': 'blocked',
})
self.contract.write(self.test_contract)
self.apply_cron()
@@ -40,19 +47,21 @@ class TestHrContracts(TestContractBase):
self.test_contract.update(dict(date_end=False))
self.contract = self.contracts.create(self.test_contract)
self.apply_cron()
- self.assertEquals(self.contract.state, 'pending')
+ self.assertEquals(self.contract.state, 'open')
+ self.assertEquals(self.contract.kanban_state, 'blocked')
self.employee.visa_expire = date.today() + relativedelta(days=-5)
self.test_contract.update({
'date_start': datetime.now() + relativedelta(days=-50),
- 'state': 'pending',
+ 'state': 'open',
+ 'kanban_state': 'blocked',
})
self.contract.write(self.test_contract)
self.apply_cron()
self.assertEquals(self.contract.state, 'close')
def test_contract_start_date(self):
- self.test_contract.update(dict(date_start=datetime.now(), state='incoming'))
+ self.test_contract.update(dict(date_start=datetime.now(), state='draft', kanban_state='done'))
self.contract = self.contracts.create(self.test_contract)
self.apply_cron()
self.assertEquals(self.contract.state, 'open')
diff --git a/addons/hr_contract/tests/test_contract.py b/addons/hr_contract/tests/test_contract.py
index ca05600929c..3d339c4c101 100644
--- a/addons/hr_contract/tests/test_contract.py
+++ b/addons/hr_contract/tests/test_contract.py
@@ -12,11 +12,12 @@ class TestHrContracts(TestContractBase):
super(TestHrContracts, self).setUp()
self.contracts = self.env['hr.contract'].with_context(tracking_disable=True)
- def create_contract(self, state, start, end=None):
+ def create_contract(self, state, kanban_state, start, end=None):
return self.env['hr.contract'].create({
'name': 'Contract',
'employee_id': self.employee.id,
'state': state,
+ 'kanban_state': kanban_state,
'wage': 1,
'date_start': start,
'date_end': end,
@@ -25,65 +26,65 @@ class TestHrContracts(TestContractBase):
def test_incoming_overlapping_contract(self):
start = datetime.strptime('2015-11-01', '%Y-%m-%d').date()
end = datetime.strptime('2015-11-30', '%Y-%m-%d').date()
- self.create_contract('open', start, end)
+ self.create_contract('open', 'normal', start, end)
# Incoming contract
with self.assertRaises(ValidationError, msg="It should not create two contract in state open or incoming"):
start = datetime.strptime('2015-11-15', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('incoming', start, end)
+ self.create_contract('draft', 'done', start, end)
def test_pending_overlapping_contract(self):
start = datetime.strptime('2015-11-01', '%Y-%m-%d').date()
end = datetime.strptime('2015-11-30', '%Y-%m-%d').date()
- self.create_contract('open', start, end)
+ self.create_contract('open', 'normal', start, end)
# Pending contract
with self.assertRaises(ValidationError, msg="It should not create two contract in state open or pending"):
start = datetime.strptime('2015-11-15', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('pending', start, end)
+ self.create_contract('open', 'blocked', start, end)
# Draft contract -> should not raise
start = datetime.strptime('2015-11-15', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('draft', start, end)
+ self.create_contract('draft', 'normal', start, end)
def test_draft_overlapping_contract(self):
start = datetime.strptime('2015-11-01', '%Y-%m-%d').date()
end = datetime.strptime('2015-11-30', '%Y-%m-%d').date()
- self.create_contract('open', start, end)
+ self.create_contract('open', 'normal', start, end)
# Draft contract -> should not raise even if overlapping
start = datetime.strptime('2015-11-15', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('draft', start, end)
+ self.create_contract('draft', 'normal', start, end)
def test_overlapping_contract_no_end(self):
# No end date
- self.create_contract('open', datetime.strptime('2015-11-01', '%Y-%m-%d').date())
+ self.create_contract('open', 'normal', datetime.strptime('2015-11-01', '%Y-%m-%d').date())
with self.assertRaises(ValidationError):
start = datetime.strptime('2015-11-15', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('incoming', start, end)
+ self.create_contract('draft', 'done', start, end)
def test_overlapping_contract_no_end2(self):
start = datetime.strptime('2015-11-01', '%Y-%m-%d').date()
end = datetime.strptime('2015-12-30', '%Y-%m-%d').date()
- self.create_contract('open', start, end)
+ self.create_contract('open', 'normal', start, end)
with self.assertRaises(ValidationError):
# No end
- self.create_contract('incoming', datetime.strptime('2015-01-01', '%Y-%m-%d').date())
+ self.create_contract('draft', 'done', datetime.strptime('2015-01-01', '%Y-%m-%d').date())
def test_set_employee_contract_create(self):
- contract = self.create_contract('open', date(2018, 1, 1), date(2018, 1, 2))
+ contract = self.create_contract('open', 'normal', date(2018, 1, 1), date(2018, 1, 2))
self.assertEqual(self.employee.contract_id, contract)
def test_set_employee_contract_write(self):
- contract = self.create_contract('draft', date(2018, 1, 1), date(2018, 1, 2))
+ contract = self.create_contract('draft', 'normal', date(2018, 1, 1), date(2018, 1, 2))
contract.state = 'open'
self.assertEqual(self.employee.contract_id, contract)
diff --git a/addons/hr_contract/views/assets.xml b/addons/hr_contract/views/assets.xml
new file mode 100644
index 00000000000..f482256b4ae
--- /dev/null
+++ b/addons/hr_contract/views/assets.xml
@@ -0,0 +1,7 @@
+<odoo>
+ <template id="assets_backend" inherit_id="web.assets_backend">
+ <xpath expr="." position="inside">
+ <link rel="stylesheet" type="text/css" href="/hr_contract/static/src/scss/state_selection.scss"/>
+ </xpath>
+ </template>
+</odoo> \ No newline at end of file
diff --git a/addons/hr_contract/views/hr_contract_views.xml b/addons/hr_contract/views/hr_contract_views.xml
index a1c9c3cd843..ecf835d094c 100644
--- a/addons/hr_contract/views/hr_contract_views.xml
+++ b/addons/hr_contract/views/hr_contract_views.xml
@@ -53,6 +53,37 @@
</field>
</record>
+ <record id="hr_employee_view_kanban" model="ir.ui.view">
+ <field name="name">hr.employee.view.kanban</field>
+ <field name="model">hr.employee</field>
+ <field name="inherit_id" ref="hr.hr_kanban_view_employees"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//div[hasclass('o_kanban_record_headings')]" position="after">
+ <field name="contract_warning" invisible="1"/>
+ <t t-if="record.contract_warning.raw_value">
+ <i class="fa fa-exclamation-triangle text-danger" role="img"
+ title="There is something wrong with the contract. Either there is no running contract for this employee or employee's contract is about to expire."
+ aria-label="There is something wrong with the contract. Either there is no running contract for this employee or employee's contract is about to expire."></i>
+ </t>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
+ <record id="hr_employee_view_search" model="ir.ui.view">
+ <field name="name">hr.employee.view.search</field>
+ <field name="model">hr.employee</field>
+ <field name="inherit_id" ref="hr.view_employee_filter"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="." position="inside">
+ <filter string="Contract Warning" name="with_contract_warning" domain="[('contract_warning', '=', True)]"/>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
<record id="hr_user_view_form" model="ir.ui.view">
<field name="name">hr.user.preferences.view.form.contract.inherit</field>
<field name="model">res.users</field>
@@ -83,7 +114,7 @@
<field name="department_id" operator="child_of"/>
<field name="state"/>
<filter string="Running" name="running" domain="[('state', '=', 'open')]"/>
- <filter string="To Renew" name="to_renew" domain="[('state', '=', 'pending')]"/>
+ <filter string="To Renew / Expires Soon" name="to_renew" domain="['&amp;', ('state', '=', 'open'), ('kanban_state', '=', 'blocked')]"/>
<separator />
<filter string="Current Employee" name="current_employee" domain="[('employee_id.active','=',True)]"/>
<separator/>
@@ -114,8 +145,16 @@
</button>
</div>
<div class="oe_title" name="title">
- <label for="name" class="oe_edit_only"/>
+ <div class="oe_edit_only">
+ <div class="float-left">
+ <field name="kanban_state" widget="state_selection" class="mr-2"/>
+ </div>
+ <label for="name"/>
+ </div>
<h1>
+ <div class="float-left oe_read_only">
+ <field name="kanban_state" widget="state_selection" class="mr-2"/>
+ </div>
<field name="name" placeholder="Contract Reference"/>
</h1>
</div>
@@ -143,7 +182,7 @@
<label for="resource_calendar_id"/>
<div>
<field name="resource_calendar_id" required="1" nolabel="1"/>
- <span attrs="{'invisible': ['|', ('calendar_mismatch', '=', False), ('state', 'not in', ['open', 'pending'])]}"
+ <span attrs="{'invisible': ['|', ('calendar_mismatch', '=', False), ('state', '!=', 'open')]}"
class="fa fa-exclamation-triangle text-danger o_calendar_warning pl-3">
</span>
<span class="o_calendar_warning_tooltip text-danger">
@@ -196,6 +235,7 @@
<field name="date_start"/>
<field name="date_end"/>
<field name="state"/>
+ <field name="kanban_state" widget="state_selection" readonly="1"/>
<field name="wage" invisible="1"/>
<field name="message_needaction" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
@@ -207,9 +247,10 @@
<field name="name">hr.contract.kanban</field>
<field name="model">hr.contract</field>
<field name="arch" type="xml">
- <kanban class="o_kanban_small_column">
+ <kanban class="o_kanban_small_column" default_order="date_end">
<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">
@@ -224,10 +265,13 @@
</div>
</div>
<div class="oe_kanban_content">
- <div>
- <strong class="o_kanban_record_title"><field name="name"/></strong>
+ <div class="o_hr_contract_state">
+ <field name="kanban_state" widget="state_selection" />
+ <strong class="o_kanban_record_title">
+ <field name="name"/>
+ </strong>
</div>
- <div class="text-muted o_kanban_record_subtitle">
+ <div class="text-muted o_kanban_record_subtitle o_hr_contract_job_id">
<field name="job_id"/>
</div>
<div class="oe_kanban_bottom_right">