diff --git a/addons/hr_contract/models/hr_contract.py b/addons/hr_contract/models/hr_contract.py index 4b931f9e50c..b3b59023949 100644 --- a/addons/hr_contract/models/hr_contract.py +++ b/addons/hr_contract/models/hr_contract.py @@ -19,9 +19,9 @@ class Contract(models.Model): employee_id = fields.Many2one('hr.employee', string='Employee', tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]") department_id = fields.Many2one('hr.department', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", string="Department") job_id = fields.Many2one('hr.job', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", string='Job Position') - date_start = fields.Date('Start Date', required=True, default=fields.Date.today, + date_start = fields.Date('Start Date', required=True, default=fields.Date.today, tracking=True, help="Start date of the contract.") - date_end = fields.Date('End Date', + date_end = fields.Date('End Date', tracking=True, help="End date of the contract (if it's a fixed-term contract).") trial_date_end = fields.Date('End of Trial Period', help="End date of the trial period (if there is one).") @@ -133,6 +133,26 @@ class Contract(models.Model): self.search([('state', '=', 'draft'), ('kanban_state', '=', 'done'), ('date_start', '<=', fields.Date.to_string(date.today())),]).write({ 'state': 'open' }) + + contract_ids = self.search([('date_end', '=', False), ('state', '=', 'close'), ('employee_id', '!=', False)]) + # Ensure all closed contract followed by a new contract have a end date. + # If closed contract has no closed date, the work entries will be generated for an unlimited period. + for contract in contract_ids: + next_contract = self.search([ + ('employee_id', '=', contract.employee_id.id), + ('state', 'not in', ['cancel', 'new']), + ('date_start', '>', contract.date_start) + ], order="date_start asc", limit=1) + if next_contract: + contract.date_end = next_contract.date_start - relativedelta(days=1) + continue + next_contract = self.search([ + ('employee_id', '=', contract.employee_id.id), + ('date_start', '>', contract.date_start) + ], order="date_start asc", limit=1) + if next_contract: + contract.date_end = next_contract.date_start - relativedelta(days=1) + return True def _assign_open_contract(self): @@ -143,6 +163,9 @@ class Contract(models.Model): res = super(Contract, self).write(vals) if vals.get('state') == 'open': self._assign_open_contract() + if vals.get('state') == 'close': + for contract in self.filtered(lambda c: not c.date_end): + contract.date_end = max(date.today(), contract.date_start) calendar = vals.get('resource_calendar_id') if calendar: diff --git a/addons/hr_work_entry/views/hr_work_entry_views.xml b/addons/hr_work_entry/views/hr_work_entry_views.xml index 3fefedddf6a..b04e84e644f 100644 --- a/addons/hr_work_entry/views/hr_work_entry_views.xml +++ b/addons/hr_work_entry/views/hr_work_entry_views.xml @@ -40,7 +40,7 @@
- +
@@ -73,8 +73,8 @@ hr.work.entry - - + + @@ -93,9 +93,13 @@ + + diff --git a/addons/resource/models/resource.py b/addons/resource/models/resource.py index 24977ae0284..d24820b1c7d 100644 --- a/addons/resource/models/resource.py +++ b/addons/resource/models/resource.py @@ -316,9 +316,9 @@ class ResourceCalendar(models.Model): # -------------------------------------------------- # Computation API # -------------------------------------------------- - def _attendance_intervals(self, start_dt, end_dt, resource=None, domain=None): + def _attendance_intervals(self, start_dt, end_dt, resource=None, domain=None, tz=None): """ Return the attendance intervals in the given datetime range. - The returned intervals are expressed in the resource's timezone. + The returned intervals are expressed in specified tz or in the resource's timezone. """ assert start_dt.tzinfo and end_dt.tzinfo combine = datetime.combine @@ -331,8 +331,8 @@ class ResourceCalendar(models.Model): ('display_type', '=', False), ]]) - # express all dates and times in the resource's timezone - tz = timezone((resource or self).tz) + # express all dates and times in specified tz or in the resource's timezone + tz = tz if tz else timezone((resource or self).tz) start_dt = start_dt.astimezone(tz) end_dt = end_dt.astimezone(tz) @@ -366,9 +366,9 @@ class ResourceCalendar(models.Model): return Intervals(result) - def _leave_intervals(self, start_dt, end_dt, resource=None, domain=None): + def _leave_intervals(self, start_dt, end_dt, resource=None, domain=None, tz=None): """ Return the leave intervals in the given datetime range. - The returned intervals are expressed in the calendar's timezone. + The returned intervals are expressed in specified tz or in the calendar's timezone. """ assert start_dt.tzinfo and end_dt.tzinfo self.ensure_one() @@ -385,7 +385,7 @@ class ResourceCalendar(models.Model): ] # retrieve leave intervals in (start_dt, end_dt) - tz = timezone((resource or self).tz) + tz = tz if tz else timezone((resource or self).tz) start_dt = start_dt.astimezone(tz) end_dt = end_dt.astimezone(tz) result = [] @@ -396,10 +396,10 @@ class ResourceCalendar(models.Model): return Intervals(result) - def _work_intervals(self, start_dt, end_dt, resource=None, domain=None): + def _work_intervals(self, start_dt, end_dt, resource=None, domain=None, tz=None): """ Return the effective work intervals between the given datetimes. """ - return (self._attendance_intervals(start_dt, end_dt, resource) - - self._leave_intervals(start_dt, end_dt, resource, domain)) + return (self._attendance_intervals(start_dt, end_dt, resource, tz=tz) - + self._leave_intervals(start_dt, end_dt, resource, domain, tz=tz)) # -------------------------------------------------- # Private Methods / Helpers