summaryrefslogtreecommitdiff
path: root/addons/hr_holidays/tests/test_holidays_flow.py
blob: b63c4486a5d09346201ce6bcd504c34d791ae908 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import time
from datetime import datetime
from dateutil.relativedelta import relativedelta
from psycopg2 import IntegrityError

from odoo import fields
from odoo.exceptions import AccessError, ValidationError, UserError
from odoo.tools import mute_logger, test_reports

from odoo.addons.hr_holidays.tests.common import TestHrHolidaysCommon


class TestHolidaysFlow(TestHrHolidaysCommon):

    @mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
    def test_00_leave_request_flow_unlimited(self):
        """ Testing leave request flow: unlimited type of leave request """
        Requests = self.env['hr.leave']
        HolidaysStatus = self.env['hr.leave.type']

        # HrManager creates some holiday statuses
        HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
        HolidayStatusManagerGroup.create({
            'name': 'WithMeetingType',
            'allocation_type': 'no',
        })
        self.holidays_status_hr = HolidayStatusManagerGroup.create({
            'name': 'NotLimitedHR',
            'allocation_type': 'no',
            'leave_validation_type': 'hr',
            'validity_start': False,
        })
        self.holidays_status_manager = HolidayStatusManagerGroup.create({
            'name': 'NotLimitedManager',
            'allocation_type': 'no',
            'leave_validation_type': 'manager',
            'validity_start': False,
        })

        HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)

        # Employee creates a leave request in a no-limit category hr manager only
        hol1_employee_group = HolidaysEmployeeGroup.create({
            'name': 'Hol11',
            'employee_id': self.employee_emp_id,
            'holiday_status_id': self.holidays_status_hr.id,
            'date_from': (datetime.today() - relativedelta(days=1)),
            'date_to': datetime.today(),
            'number_of_days': 1,
        })
        hol1_user_group = hol1_employee_group.with_user(self.user_hruser_id)
        hol1_manager_group = hol1_employee_group.with_user(self.user_hrmanager_id)
        self.assertEqual(hol1_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')

        # HrUser validates the employee leave request -> should work
        hol1_user_group.action_approve()
        self.assertEqual(hol1_manager_group.state, 'validate', 'hr_holidays: validated leave request should be in validate state')

        # Employee creates a leave request in a no-limit category department manager only
        hol12_employee_group = HolidaysEmployeeGroup.create({
            'name': 'Hol12',
            'employee_id': self.employee_emp_id,
            'holiday_status_id': self.holidays_status_manager.id,
            'date_from': (datetime.today() + relativedelta(days=12)),
            'date_to': (datetime.today() + relativedelta(days=13)),
            'number_of_days': 1,
        })
        hol12_user_group = hol12_employee_group.with_user(self.user_hruser_id)
        hol12_manager_group = hol12_employee_group.with_user(self.user_hrmanager_id)
        self.assertEqual(hol12_user_group.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state')

        # HrManager validate the employee leave request
        hol12_manager_group.action_approve()
        self.assertEqual(hol1_user_group.state, 'validate', 'hr_holidays: validates leave request should be in validate state')


    @mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
    def test_01_leave_request_flow_limited(self):
        """ Testing leave request flow: limited type of leave request """
        Requests = self.env['hr.leave']
        Allocations = self.env['hr.leave.allocation']
        HolidaysStatus = self.env['hr.leave.type']

        holiday_status_paid_time_off = self.env['hr.leave.type'].create({
            'name': 'Paid Time Off',
            'allocation_type': 'fixed',
            'leave_validation_type': 'both',
            'validity_start': time.strftime('%Y-%m-01'),
            'responsible_id': self.env.ref('base.user_admin').id,
        })

        self.env['hr.leave.allocation'].create([
            {
                'name': 'Paid Time off for David',
                'holiday_status_id': holiday_status_paid_time_off.id,
                'number_of_days': 20,
                'employee_id': self.employee_emp_id,
                'state': 'validate',
            }, {
                'name': 'Paid Time off for David',
                'holiday_status_id': holiday_status_paid_time_off.id,
                'number_of_days': 20,
                'employee_id': self.ref('hr.employee_admin'),
                'state': 'validate',
            }
        ])

        def _check_holidays_status(holiday_status, ml, lt, rl, vrl):
            self.assertEqual(holiday_status.max_leaves, ml,
                             'hr_holidays: wrong type days computation')
            self.assertEqual(holiday_status.leaves_taken, lt,
                             'hr_holidays: wrong type days computation')
            self.assertEqual(holiday_status.remaining_leaves, rl,
                             'hr_holidays: wrong type days computation')
            self.assertEqual(holiday_status.virtual_remaining_leaves, vrl,
                             'hr_holidays: wrong type days computation')

        # HrManager creates some holiday statuses
        HolidayStatusManagerGroup = HolidaysStatus.with_user(self.user_hrmanager_id)
        HolidayStatusManagerGroup.create({
            'name': 'WithMeetingType',
            'allocation_type': 'no',
            'validity_start': False,
        })

        self.holidays_status_limited = HolidayStatusManagerGroup.create({
            'name': 'Limited',
            'allocation_type': 'fixed',
            'allocation_validation_type': 'both',
            'leave_validation_type': 'both',
            'validity_start': False,
        })
        HolidaysEmployeeGroup = Requests.with_user(self.user_employee_id)

        # HrUser allocates some leaves to the employee
        aloc1_user_group = Allocations.with_user(self.user_hruser_id).create({
            'name': 'Days for limited category',
            'employee_id': self.employee_emp_id,
            'holiday_status_id': self.holidays_status_limited.id,
            'number_of_days': 2,
        })
        # HrUser validates the first step
        aloc1_user_group.action_approve()

        # HrManager validates the second step
        aloc1_user_group.with_user(self.user_hrmanager_id).action_validate()
        # Checks Employee has effectively some days left
        hol_status_2_employee_group = self.holidays_status_limited.with_user(self.user_employee_id)
        _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0)

        # Employee creates a leave request in the limited category, now that he has some days left
        hol2 = HolidaysEmployeeGroup.create({
            'name': 'Hol22',
            'employee_id': self.employee_emp_id,
            'holiday_status_id': self.holidays_status_limited.id,
            'date_from': (datetime.today() + relativedelta(days=2)).strftime('%Y-%m-%d %H:%M'),
            'date_to': (datetime.today() + relativedelta(days=3)),
            'number_of_days': 1,
        })
        hol2_user_group = hol2.with_user(self.user_hruser_id)
        # Check left days: - 1 virtual remaining day
        hol_status_2_employee_group.invalidate_cache()
        _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 1.0)

        # HrManager validates the first step
        hol2_user_group.with_user(self.user_hrmanager_id).action_approve()
        self.assertEqual(hol2.state, 'validate1',
                         'hr_holidays: first validation should lead to validate1 state')

        # HrManager validates the second step
        hol2_user_group.with_user(self.user_hrmanager_id).action_validate()
        self.assertEqual(hol2.state, 'validate',
                         'hr_holidays: second validation should lead to validate state')
        # Check left days: - 1 day taken
        _check_holidays_status(hol_status_2_employee_group, 2.0, 1.0, 1.0, 1.0)

        # HrManager finds an error: he refuses the leave request
        hol2.with_user(self.user_hrmanager_id).action_refuse()
        self.assertEqual(hol2.state, 'refuse',
                         'hr_holidays: refuse should lead to refuse state')
        # Check left days: 2 days left again

        hol_status_2_employee_group.invalidate_cache(['max_leaves'])
        _check_holidays_status(hol_status_2_employee_group, 2.0, 0.0, 2.0, 2.0)

        self.assertEqual(hol2.state, 'refuse',
                         'hr_holidays: hr_user should not be able to reset a refused leave request')

        # HrManager resets the request
        hol2_manager_group = hol2.with_user(self.user_hrmanager_id)
        hol2_manager_group.action_draft()
        self.assertEqual(hol2.state, 'draft',
                         'hr_holidays: resetting should lead to draft state')

        employee_id = self.ref('hr.employee_admin')
        # cl can be of maximum 20 days for employee_admin
        hol3_status = holiday_status_paid_time_off.with_context(employee_id=employee_id)
        # I assign the dates in the holiday request for 1 day
        hol3 = Requests.create({
            'name': 'Sick Time Off',
            'holiday_status_id': hol3_status.id,
            'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'),
            'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'),
            'employee_id': employee_id,
            'number_of_days': 1,
        })
        # I find a small mistake on my leave request to I click on "Refuse" button to correct a mistake.
        hol3.action_refuse()
        self.assertEqual(hol3.state, 'refuse', 'hr_holidays: refuse should lead to refuse state')
        # I again set to draft and then confirm.
        hol3.action_draft()
        self.assertEqual(hol3.state, 'draft', 'hr_holidays: resetting should lead to draft state')
        hol3.action_confirm()
        self.assertEqual(hol3.state, 'confirm', 'hr_holidays: confirming should lead to confirm state')
        # I validate the holiday request by clicking on "To Approve" button.
        hol3.action_approve()
        hol3.action_validate()
        self.assertEqual(hol3.state, 'validate', 'hr_holidays: validation should lead to validate state')
        # Check left days for casual leave: 19 days left
        _check_holidays_status(hol3_status, 20.0, 1.0, 19.0, 19.0)

    def test_10_leave_summary_reports(self):
        # Print the HR Holidays(Summary Employee) Report through the wizard
        ctx = {
            'model': 'hr.employee',
            'active_ids': [self.ref('hr.employee_admin')]
        }
        data_dict = {
            'date_from': datetime.today().strftime('%Y-%m-01'),
            'emp': [(6, 0, [self.ref('hr.employee_admin')])],
            'holiday_type': 'Approved'
        }
        self.env.company.external_report_layout_id = self.env.ref('web.external_layout_standard').id
        test_reports.try_report_action(self.env.cr, self.env.uid, 'action_hr_holidays_summary_employee', wiz_data=data_dict, context=ctx, our_module='hr_holidays')

    def test_sql_constraint_dates(self):
        # The goal is mainly to verify that a human friendly
        # error message is triggered if the date_from is after
        # date_to. Coming from a bug due to the new ORM 13.0

        holiday_status_paid_time_off = self.env['hr.leave.type'].create({
            'name': 'Paid Time Off',
            'allocation_type': 'fixed',
            'leave_validation_type': 'both',
            'validity_start': time.strftime('%Y-%m-01'),
            'responsible_id': self.env.ref('base.user_admin').id,
        })

        self.env['hr.leave.allocation'].create({
            'name': 'Paid Time off for David',
            'holiday_status_id': holiday_status_paid_time_off.id,
            'number_of_days': 20,
            'employee_id': self.ref('hr.employee_admin'),
            'state': 'validate',
        })

        leave_vals = {
            'name': 'Sick Time Off',
            'holiday_status_id': holiday_status_paid_time_off.id,
            'date_from': datetime.today().strftime('%Y-%m-11 19:00:00'),
            'date_to': datetime.today().strftime('%Y-%m-10 10:00:00'),
            'employee_id': self.ref('hr.employee_admin'),
            'number_of_days': 1,
        }
        with mute_logger('odoo.sql_db'):
            with self.assertRaises(IntegrityError):
                with self.cr.savepoint():
                    self.env['hr.leave'].create(leave_vals)

        leave_vals = {
            'name': 'Sick Time Off',
            'holiday_status_id': holiday_status_paid_time_off.id,
            'date_from': datetime.today().strftime('%Y-%m-10 10:00:00'),
            'date_to': datetime.today().strftime('%Y-%m-11 19:00:00'),
            'employee_id': self.ref('hr.employee_admin'),
            'number_of_days': 1,
        }
        leave = self.env['hr.leave'].create(leave_vals)
        with mute_logger('odoo.sql_db'):
            with self.assertRaises(IntegrityError):  # No ValidationError
                with self.cr.savepoint():
                    leave.write({
                        'date_from': datetime.today().strftime('%Y-%m-11 19:00:00'),
                        'date_to': datetime.today().strftime('%Y-%m-10 10:00:00'),
                    })