From dc580c6c60660f1f69b5ad978491eac466ce054a Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 1 May 2018 10:48:17 +0200 Subject: [PATCH] [ADD] when approving a timesheet, create leaves if necessary --- hr_timesheet_holiday/README.rst | 7 +- hr_timesheet_holiday/__openerp__.py | 2 +- hr_timesheet_holiday/models/__init__.py | 1 + .../models/hr_timesheet_sheet.py | 53 +++++++++++++ hr_timesheet_holiday/tests/test_all.py | 76 ++++++++++++++----- 5 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 hr_timesheet_holiday/models/hr_timesheet_sheet.py diff --git a/hr_timesheet_holiday/README.rst b/hr_timesheet_holiday/README.rst index 78473c7b3d..2fcf52506e 100644 --- a/hr_timesheet_holiday/README.rst +++ b/hr_timesheet_holiday/README.rst @@ -8,7 +8,9 @@ Link holidays to analytic lines This module adds a relation between Leave Type and Analytic Account. When a Leave Request is granted, the granted days are converted to hours and -added as a line to the Analytic Account. +added as a line to the Analytic Account. Conversely, when a timesheet line +with an analytic account pointed to by a Leave Type is approved, this will +result in an approved leave request. When the leave is revoked, the analytic lines are removed again. @@ -48,9 +50,6 @@ Known issues / Roadmap To make this easier, the function `_get_hours_per_day` was made which can be overridden by child modules. * We should probably start using resource calendars. -* hr_timesheet_sheet dependency can be changed to hr_timesheet, now only - included because hr_timesheet_sheet adds the Timesheet configurations menu - in Company view. Bug Tracker =========== diff --git a/hr_timesheet_holiday/__openerp__.py b/hr_timesheet_holiday/__openerp__.py index efd35b0428..0a7644338b 100644 --- a/hr_timesheet_holiday/__openerp__.py +++ b/hr_timesheet_holiday/__openerp__.py @@ -4,7 +4,7 @@ { 'name': 'Link holidays to analytic lines', - 'version': '8.0.1.0.0', + 'version': '8.0.1.1.0', 'category': 'Generic Modules/Human Resources', 'summary': """When holidays are granted, add lines to the analytic account that is linked to the Leave Type""", diff --git a/hr_timesheet_holiday/models/__init__.py b/hr_timesheet_holiday/models/__init__.py index e6065b2083..d56bcc483a 100644 --- a/hr_timesheet_holiday/models/__init__.py +++ b/hr_timesheet_holiday/models/__init__.py @@ -6,3 +6,4 @@ from . import company from . import hr_holidays from . import hr_holidays_status +from . import hr_timesheet_sheet diff --git a/hr_timesheet_holiday/models/hr_timesheet_sheet.py b/hr_timesheet_holiday/models/hr_timesheet_sheet.py new file mode 100644 index 0000000000..3c9e1e7adb --- /dev/null +++ b/hr_timesheet_holiday/models/hr_timesheet_sheet.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# © 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from openerp import api, models + + +class HrTimesheetSheet(models.Model): + _inherit = 'hr_timesheet_sheet.sheet' + + @api.multi + def write(self, vals): + result = super(HrTimesheetSheet, self).write(vals) + if vals.get('state') == 'done': + self._timesheet_approved() + return result + + @api.multi + def _timesheet_approved(self): + requests = [] + for this in self: + holiday2hours = {} + for line in this.mapped('timesheet_ids'): + holiday = line.account_id.holiday_status_ids[:1] + if not holiday: + continue + holiday2hours.setdefault(holiday, 0.0) + holiday2hours[holiday] += line.unit_amount + for holiday, hours in holiday2hours.iteritems(): + request = self.env['hr.holidays'].sudo(this.user_id).create({ + 'name': '%s: %s' % (this.name, holiday.name), + 'user_id': this.user_id.id, + 'date_from': this.date_from, + 'date_to': this.date_to, + 'holiday_status_id': holiday.id, + 'number_of_days_temp': + hours / self.env['hr.holidays']._get_hours_per_day( + this.employee_id.company_id, this.employee_id, + ), + 'type': 'remove', + 'holiday_type': 'employee', + }) + request.signal_workflow('confirm') + request.sudo(self.env.user).signal_workflow('validate') + request.sudo(self.env.user).signal_workflow('second_validate') + # circumvent all constraints here + models.Model.write( + this.mapped('timesheet_ids').filtered( + lambda x: x.account_id.holiday_status_ids & holiday + ), + {'leave_id': request.id} + ) + requests.append(request) + return requests diff --git a/hr_timesheet_holiday/tests/test_all.py b/hr_timesheet_holiday/tests/test_all.py index 17959eea46..a08a988e82 100644 --- a/hr_timesheet_holiday/tests/test_all.py +++ b/hr_timesheet_holiday/tests/test_all.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- # © 2016 Sunflower IT (http://sunflowerweb.nl) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - import time - +from openerp.tools import float_round from openerp.tests.common import TransactionCase from openerp.exceptions import ValidationError @@ -11,31 +10,28 @@ class TimesheetHolidayTest(TransactionCase): def setUp(self): super(TimesheetHolidayTest, self).setUp() - self.leave = self.env['hr.holidays'] - self.account = self.env['account.analytic.account'] - - # Create a test customer - def test_all(self): # Working day is 7 hours per day self.env.ref('base.main_company') \ .timesheet_hours_per_day = 7.0 # Create analytic account - account = self.account.create({ + self.account = self.env['account.analytic.account'].create({ 'name': 'Sick Leaves', - 'is_leave_account': True + 'is_leave_account': True, + 'type': 'normal', }) # Link sick leave to analytic account - sl = self.env.ref('hr_holidays.holiday_status_sl') - sl.write({ - 'analytic_account_id': account.id + self.sl = self.env.ref('hr_holidays.holiday_status_sl') + self.sl.write({ + 'analytic_account_id': self.account.id }) + def test_leave(self): # Create sick leave for Pieter Parker - leave = self.leave.create({ + leave = self.env['hr.holidays'].create({ 'name': 'One week sick leave', - 'holiday_status_id': sl.id, + 'holiday_status_id': self.sl.id, 'date_from': time.strftime('%Y-%m-06'), 'date_to': time.strftime('%Y-%m-12'), 'number_of_days_temp': 7.0, @@ -43,26 +39,66 @@ def test_all(self): }) # Confirm leave and check hours added to account - hours_before = sum(account.line_ids.mapped('amount')) + hours_before = sum(self.account.line_ids.mapped('amount')) leave.signal_workflow('confirm') leave.signal_workflow('validate') leave.signal_workflow('second_validate') - hours_after = sum(account.line_ids.mapped('unit_amount')) + hours_after = sum(self.account.line_ids.mapped('unit_amount')) self.assertEqual(hours_after - hours_before, 35.0) # Test editing of lines forbidden - self.assertRaises(ValidationError, account.line_ids[0].write, { + self.assertRaises(ValidationError, self.account.line_ids[0].write, { 'unit_amount': 5.0 }) # Test force editing of lines allowed - account.line_ids[0].with_context(force_write=True).write({ + self.account.line_ids[0].with_context(force_write=True).write({ 'unit_amount': 5.0 }) - hours_after = sum(account.line_ids.mapped('unit_amount')) + hours_after = sum(self.account.line_ids.mapped('unit_amount')) self.assertEqual(hours_after - hours_before, 33.0) # Refuse leave and check hours removed from account leave.signal_workflow('refuse') - hours_final = sum(account.line_ids.mapped('unit_amount')) + hours_final = sum(self.account.line_ids.mapped('unit_amount')) self.assertEqual(hours_final, hours_before) + + def test_analytic(self): + manager = self.env.ref('hr.employee_fp') + employee = self.env.ref('hr.employee_qdp') + employee.write(employee.default_get(['product_id', 'journal_id'])) + line = self.env['hr.analytic.timesheet'].sudo( + employee.user_id, + ).default_get([ + 'general_account_id', 'journal_id', 'name', 'product_id', + 'product_uom_id', + ]) + line.update(self.env['hr.analytic.timesheet'].on_change_account_id( + self.account.id, employee.user_id.id + )['value']) + line.update( + account_id=self.account.id, + date=time.strftime('%Y-%m-06'), + name='/', + unit_amount=6, + ) + sheet = self.env['hr_timesheet_sheet.sheet'].sudo( + employee.user_id + ).create({ + 'employee_id': employee.id, + 'date_from': time.strftime('%Y-%m-06'), + 'date_to': time.strftime('%Y-%m-12'), + 'timesheet_ids': [(0, 0, line)], + }) + sheet.signal_workflow('confirm') + leaves_taken_before = self.account.holiday_status_ids.sudo( + employee.user_id + ).leaves_taken + sheet.sudo(manager.user_id).signal_workflow('done') + leaves_taken_after = self.account.holiday_status_ids.sudo( + employee.user_id + ).leaves_taken + self.assertEqual( + float_round(leaves_taken_before + 6.0 / 7.0, 2), + float_round(leaves_taken_after, 2), + )