[IMP] hr_holidays: Improve general UX (back2basics)
Purpose ======= Having a clean policy in leave access right. If there are some internal need or bugs, read this before decided if it is an expected brhavior or not. It is what we want in a standrard point of vew. Specification ============= Access rights Policy -------------------- Remove Time Off - Team Leader access right Leave_manager_id is now requried, by default it is = parent_id for admin it is admin by default (data employee_admin) 3 access rights: - Internal User - Time Off - All Approver - Time Off - Administrator 3 fields for "manager" - parent_id - leave_manager_id - manager_id on department Department Is just there for information. So never use it in default filters Rules Policy ------------ Don't forget to take the leave type configuration into account * no validation means automatic * officer validation means you need to be at least holidays_user to approve * manager validation means anyone who is at least leave_manager_id can approve Internal User ------------- In double validation mode he: - can only do the first approval - can see the everyone's leaves with a anonymisation of the leave description - can create a leave (even if leave type is directly approved) - can refuse its own leaves (till not reported in payslip) - can reset to draft his own leaves and reconfirm them - can delete a leave in draft state - can cancel a leave if the date_start is in the future - cannot validate its own leaves If leave type is configured in manager mode, he: - can approve or refuse the leaves if he is leave_manager_id If leave type is configured in both mode, he: - can only do the first approval or refuse for the leave if he is leave_manager_id Time Off - All Approver ----------------------- In double validation mode he: - can only do the second approval - can see, write, read all leaves and perform the second approval. - Can set a leaves as reported in payslip. - Cannot validate its own leaves - cannot configure leave type - cannot create leaves in batch Time Off - Administrator ------------------------ In double validation mode he: - can do all the approvals - can bypass all leaves (approve or refuse). - can configure Time Off Types - can create batch leaves - can validate its own leaves Menu ---- - My Time Off (access rights: internal user) - Dashboard - Time Off Requests - Allocation Requests - My Team (rename into "Everyone", access rights: internal user. default filters on current year and group by employee; default view: gantt can switch to list and form) - Managers - To Approve (internal user who are leave_manager_id see and can approve. See only leave he has to approve (domain)) - Time Off - Allocation - All - Time Off - Allocation - Payroll - Time Off to report. - Reporting (access right: time off administrator) - Time Off Analysis - Report by Department - Configuration (access right: time off administrator) Usability --------- - In all list of "manager menus", add actions to change status in mass - In leave type data: - move Home Working from data to demo data - There are 2 Paid time off, get rid of the company on it and share it on all companies (keep only the one in data) - Leave type like this: - Overtime Compensation/compensatory days (keep only one of both, to avoid having 2 same leaves in demo data). Validation by: team leader and hr officer, no validity date - Paid Time Off 2019. Validation by Team Leader and Payroll Officer. Remove validity, remove 2019. - Unpaid. Can be taken in hours. Approved by Payroll officer and team leader. No allocation needed. - New leave request: order of leave type in the m2o: 1. leaves where allocation are fixed by rh and remaining > 0 and allocated > 0 2. leaves where free allocation. Where reaming is > 0 and allocated >0 3. One already taken 4. All other leaves. - Remove the sequence widget in leave type - The employee should get a notification when his leave is refused "Your "leave_type_name_" planned on "start_date" has been refused" - from the dashboard calendar, the reset to draft should lead to edit (avoid user has to click on edit) - An employee should be notified when a leave is approved "Your [leave_type_name] on [start date] has been approved" Leave Dashboard V2 ------------------ https://drive.google.com/file/d/1pMCqDlecqM7ngvmhJJdWtkG2_GiXHyIX/view?usp=sharing Testing ------- Everything concerning the leave requests has to be tested. All the access rights have been reviewed and need testing. Migration --------- Don't forget to keep the filters in the calendar view (otherwise RIP perfomances and usability) TaskID: 1950998 closes odoo/odoo#33813 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
committed by
Yannick Tivisse
parent
65613f5f83
commit
e0b16b22e8
@@ -48,6 +48,7 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
|
||||
|
||||
'views/hr_views.xml',
|
||||
'views/hr_leave_template.xml',
|
||||
'views/hr_holidays_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/hr_holidays_demo.xml',
|
||||
|
||||
@@ -3,21 +3,13 @@
|
||||
<data noupdate="1">
|
||||
<!-- Casual leave -->
|
||||
<record id="holiday_status_cl" model="hr.leave.type">
|
||||
<field name="name" eval="'Paid Time Off '+time.strftime('%Y')"/>
|
||||
<field name="name">Paid Time Off</field>
|
||||
<field name="allocation_type">fixed</field>
|
||||
<field name="validation_type">both</field>
|
||||
<field name="color_name">black</field>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave')"/>
|
||||
<field name="allocation_notif_subtype_id" eval="ref('mt_leave_allocation')"/>
|
||||
</record>
|
||||
|
||||
<!-- Home working -->
|
||||
<record id="holiday_status_hw" model="hr.leave.type">
|
||||
<field name="name">Home Workings</field>
|
||||
<field name="color_name">lightgreen</field>
|
||||
<field name="validity_start" eval="False"/>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave_home_working')"/>
|
||||
<field name="validity_start" eval="time.strftime('%Y-%m-01')"/>
|
||||
</record>
|
||||
|
||||
<!-- Sick leave -->
|
||||
@@ -33,19 +25,20 @@
|
||||
<record id="holiday_status_comp" model="hr.leave.type">
|
||||
<field name="name">Compensatory Days</field>
|
||||
<field name="allocation_type">fixed_allocation</field>
|
||||
<field name="validation_type">both</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="color_name">lavender</field>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
|
||||
<field name="validity_start" eval="False"/>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave')"/>
|
||||
</record>
|
||||
|
||||
<!--Unpaid Leave -->
|
||||
<record id="holiday_status_unpaid" model="hr.leave.type">
|
||||
<field name="name">Unpaid</field>
|
||||
<field name="allocation_type">fixed_allocation</field>
|
||||
<field name="allocation_type">no</field>
|
||||
<field name="validation_type">both</field>
|
||||
<field name="color_name">brown</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="unpaid" eval="True"/>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave_unpaid')"/>
|
||||
|
||||
@@ -3,29 +3,23 @@
|
||||
<data noupdate="1">
|
||||
|
||||
<!--Leave Type-->
|
||||
<record id="hr_holiday_status_hl" model="hr.leave.type">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="allocation_type">fixed_allocation</field>
|
||||
<field name="color_name">blue</field>
|
||||
<field name="request_unit">hour</field>
|
||||
<field name="validity_start" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holiday_status_dv" model="hr.leave.type">
|
||||
<field name="name">Parental Time Off</field>
|
||||
<field name="allocation_type">fixed</field>
|
||||
<field name="color_name">brown</field>
|
||||
<field name="validation_type">both</field>
|
||||
<field name="validity_start" eval="False"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
</record>
|
||||
|
||||
<record id="holiday_status_cla" model="hr.leave.type">
|
||||
<field name="name" eval="'Paid Time Off ' + time.strftime('%Y')"/>
|
||||
<field name="allocation_type">fixed</field>
|
||||
<field name="color_name">wheat</field>
|
||||
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
|
||||
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
|
||||
</record>
|
||||
<!-- Home working -->
|
||||
<record id="holiday_status_hw" model="hr.leave.type">
|
||||
<field name="name">Home Workings</field>
|
||||
<field name="color_name">lightgreen</field>
|
||||
<field name="leave_notif_subtype_id" eval="ref('mt_leave_home_working')"/>
|
||||
<field name="responsible_id" ref="base.user_admin"/>
|
||||
<field name="validity_start" eval="False"/>
|
||||
</record>
|
||||
|
||||
<!-- ++++++++++++++++++++++ Mitchell Admin ++++++++++++++++++++++ -->
|
||||
|
||||
@@ -34,7 +28,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_admin"/>
|
||||
<field name="state">confirm</field>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_int_tour" model="hr.leave.allocation">
|
||||
@@ -45,13 +39,6 @@
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_admin"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc" model="hr.leave.allocation">
|
||||
<field name="name">Summer Vacation</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_unpaid"/>
|
||||
@@ -59,25 +46,21 @@
|
||||
<field name="employee_id" ref="hr.employee_admin"/>
|
||||
</record>
|
||||
|
||||
<record id='hr_holidays_cl_allocation' model="hr.leave.allocation">
|
||||
<field name="name">Compensation</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_comp"/>
|
||||
<field name="number_of_days">12</field>
|
||||
<field name="employee_id" ref="hr.employee_admin"/>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_int_tour')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_hl')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- leave request -->
|
||||
<record id="hr_holidays_cl" model="hr.leave">
|
||||
@@ -118,7 +101,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_al"/>
|
||||
<field name="state">confirm</field>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_pl_al" model="hr.leave.allocation">
|
||||
@@ -136,12 +119,6 @@
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl_al')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
@@ -201,14 +178,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_mit"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl_mit" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">5</field>
|
||||
<field name="employee_id" ref="hr.employee_mit"/>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_mit" model="hr.leave.allocation">
|
||||
@@ -218,20 +188,6 @@
|
||||
<field name="employee_id" ref="hr.employee_mit"/>
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl_mit')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_hl_mit')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- leave request -->
|
||||
<record id="hr_holidays_cl_mit" model="hr.leave">
|
||||
<field name="name">Trip to Paris</field>
|
||||
@@ -255,25 +211,7 @@
|
||||
<field name="employee_id" ref="hr.employee_mit"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_sl_mit" model="hr.leave">
|
||||
<field name="name">Sleeping day</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field eval="time.strftime('%Y-%m-1')" name="date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-3')" name="date_to"/>
|
||||
<field eval="time.strftime('%Y-%m-1')" name="request_date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-3')" name="request_date_to"/>
|
||||
<field name="number_of_days">3</field>
|
||||
<field name="employee_id" ref="hr.employee_mit"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<!-- approve the leave request -->
|
||||
<function model="hr.leave" name="action_approve">
|
||||
<value model="hr.leave" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_sl_mit')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave" name="action_approve">
|
||||
<value model="hr.leave" search="[
|
||||
('state', '=', 'confirm'),
|
||||
@@ -288,14 +226,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_qdp"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl_qdp" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">5</field>
|
||||
<field name="employee_id" ref="hr.employee_qdp"/>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_qdp" model="hr.leave.allocation">
|
||||
@@ -306,12 +237,6 @@
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl_qdp')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
@@ -365,7 +290,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
<field name="state">confirm</field>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_int_tour_fpi" model="hr.leave.allocation">
|
||||
@@ -376,13 +301,6 @@
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl_fpi" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">10</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_fpi" model="hr.leave.allocation">
|
||||
<field name="name">Summer Vacation</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_unpaid"/>
|
||||
@@ -391,49 +309,14 @@
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_int_tour_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_hl_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- leave request -->
|
||||
<record id="hr_holidays_cl_fpi" model="hr.leave">
|
||||
<field name="name">Trip to NY</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field eval="time.strftime('%Y-%m-3 1:0:0')" name="date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-5 23:0:0')" name="date_to"/>
|
||||
<field eval="time.strftime('%Y-%m-3 1:0:0')" name="request_date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-5 23:0:0')" name="request_date_to"/>
|
||||
<field name="number_of_days">3</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
<record id="hr_holidays_cl_fpi_2" model="hr.leave">
|
||||
<field name="name">Trip to Barcelona</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field eval="time.strftime('%Y-%m-7 1:0:0')" name="date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-9 23:0:0')" name="date_to"/>
|
||||
<field eval="time.strftime('%Y-%m-7 1:0:0')" name="request_date_from"/>
|
||||
<field eval="time.strftime('%Y-%m-9 23:0:0')" name="request_date_to"/>
|
||||
<field name="number_of_days">3</field>
|
||||
<field name="employee_id" ref="hr.employee_fpi"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_sl_fpi" model="hr.leave">
|
||||
<field name="name">Home working</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_hw"/>
|
||||
@@ -452,20 +335,6 @@
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_sl_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave" name="action_approve">
|
||||
<value model="hr.leave" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_cl_fpi')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- refuse the leave request -->
|
||||
<function model="hr.leave" name="action_refuse">
|
||||
<value model="hr.leave" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_cl_fpi_2')])
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<!-- ++++++++++++++++++++++ Olivia ++++++++++++++++++++++ -->
|
||||
|
||||
@@ -474,14 +343,7 @@
|
||||
<field name="holiday_status_id" ref="holiday_status_cl"/>
|
||||
<field name="number_of_days">20</field>
|
||||
<field name="employee_id" ref="hr.employee_niv"/>
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl_vad" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">10</field>
|
||||
<field name="employee_id" ref="hr.employee_niv"/>
|
||||
<field name="state">validate</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_vad" model="hr.leave.allocation">
|
||||
@@ -492,18 +354,6 @@
|
||||
</record>
|
||||
|
||||
<!-- approve leave allocations -->
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_cl_vad')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
('id', 'in', [ref('hr_holidays.hr_holidays_allocation_hl_vad')])
|
||||
]"/>
|
||||
</function>
|
||||
<function model="hr.leave.allocation" name="action_approve">
|
||||
<value model="hr.leave.allocation" search="[
|
||||
('state', '=', 'confirm'),
|
||||
@@ -555,13 +405,6 @@
|
||||
<field name="state">confirm</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_allocation_hl_kim" model="hr.leave.allocation">
|
||||
<field name="name">Overtime Compensation</field>
|
||||
<field name="holiday_status_id" ref="hr_holiday_status_hl"/>
|
||||
<field name="number_of_days">10</field>
|
||||
<field name="employee_id" ref="hr.employee_jve"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_vc_kim" model="hr.leave.allocation">
|
||||
<field name="name">Summer Vacation</field>
|
||||
<field name="holiday_status_id" ref="holiday_status_unpaid"/>
|
||||
|
||||
@@ -10,14 +10,9 @@ from odoo.tools.float_utils import float_round
|
||||
class HrEmployeeBase(models.AbstractModel):
|
||||
_inherit = "hr.employee.base"
|
||||
|
||||
def _group_hr_user_domain(self):
|
||||
group = self.env.ref('hr_holidays.group_hr_holidays_team_leader', raise_if_not_found=False)
|
||||
return [('groups_id', 'in', group.ids)] if group else []
|
||||
|
||||
leave_manager_id = fields.Many2one(
|
||||
'res.users', string='Time Off',
|
||||
domain=_group_hr_user_domain,
|
||||
help="User responsible of leaves approval. Should be Team Leader or Department Manager.")
|
||||
help="User responsible of leaves approval.")
|
||||
remaining_leaves = fields.Float(
|
||||
compute='_compute_remaining_leaves', string='Remaining Paid Time Off',
|
||||
help='Total number of paid time off allocated to this employee, change this value to create allocation/time off request. '
|
||||
@@ -128,7 +123,7 @@ class HrEmployeeBase(models.AbstractModel):
|
||||
super(HrEmployeeBase, self)._onchange_parent_id()
|
||||
previous_manager = self._origin.parent_id.user_id
|
||||
manager = self.parent_id.user_id
|
||||
if manager and manager.has_group('hr.group_hr_user') and (self.leave_manager_id == previous_manager or not self.leave_manager_id):
|
||||
if manager and self.leave_manager_id == previous_manager:
|
||||
self.leave_manager_id = manager
|
||||
|
||||
def _compute_show_leaves(self):
|
||||
@@ -148,10 +143,20 @@ class HrEmployeeBase(models.AbstractModel):
|
||||
])
|
||||
return [('id', 'in', holidays.mapped('employee_id').ids)]
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if 'parent_id' in values:
|
||||
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
|
||||
values['leave_manager_id'] = values.get('leave_manager_id', manager.id)
|
||||
return super(HrEmployeeBase, self).create(values)
|
||||
|
||||
def write(self, values):
|
||||
if 'parent_id' in values:
|
||||
manager = self.env['hr.employee'].browse(values['parent_id']).user_id
|
||||
values['leave_manager_id'] = values.get('leave_manager_id', manager.id)
|
||||
res = super(HrEmployeeBase, self).write(values)
|
||||
today_date = fields.Datetime.now()
|
||||
if 'parent_id' in values or 'department_id' in values:
|
||||
today_date = fields.Datetime.now()
|
||||
hr_vals = {}
|
||||
if values.get('parent_id') is not None:
|
||||
hr_vals['manager_id'] = values['parent_id']
|
||||
|
||||
@@ -9,7 +9,7 @@ import math
|
||||
from datetime import datetime, time
|
||||
from pytz import timezone, UTC
|
||||
|
||||
from odoo import api, fields, models, tools
|
||||
from odoo import api, fields, models, SUPERUSER_ID, tools
|
||||
from odoo.addons.resource.models.resource import float_to_time, HOURS_PER_DAY
|
||||
from odoo.exceptions import AccessError, UserError, ValidationError
|
||||
from odoo.tools import float_compare
|
||||
@@ -32,9 +32,6 @@ class HolidaysRequest(models.Model):
|
||||
- can discuss on its leave requests;
|
||||
- can reset only its own leaves;
|
||||
- cannot validate any leaves;
|
||||
- a Team Leader
|
||||
- has same rights as a regular employee
|
||||
- but is able to approve employees' leaves who are in his/her team (see Employee.leave_manager_id in hr_holidays/hr.py)
|
||||
- an Officer
|
||||
- can see all leaves;
|
||||
- can validate "HR" single validation leaves from people if
|
||||
@@ -69,9 +66,10 @@ class HolidaysRequest(models.Model):
|
||||
defaults = self._default_get_request_parameters(defaults)
|
||||
|
||||
LeaveType = self.env['hr.leave.type'].with_context(employee_id=defaults.get('employee_id'), default_date_from=defaults.get('date_from', fields.Datetime.now()))
|
||||
lt = LeaveType.search([('valid', '=', True)])
|
||||
lt = LeaveType.search([('valid', '=', True)], limit=1)
|
||||
|
||||
defaults['holiday_status_id'] = lt[0].id if len(lt) > 0 else defaults.get('holiday_status_id')
|
||||
defaults['holiday_status_id'] = lt.id if lt else defaults.get('holiday_status_id')
|
||||
defaults['state'] = 'confirm' if lt and lt.validation_type != 'no_validation' else 'draft'
|
||||
return defaults
|
||||
|
||||
def _default_employee(self):
|
||||
@@ -105,7 +103,7 @@ class HolidaysRequest(models.Model):
|
||||
('refuse', 'Refused'),
|
||||
('validate1', 'Second Approval'),
|
||||
('validate', 'Approved')
|
||||
], string='Status', readonly=True, tracking=True, copy=False, default='confirm',
|
||||
], string='Status', readonly=True, tracking=True, copy=False,
|
||||
help="The status is set to 'To Submit', when a time off request is created." +
|
||||
"\nThe status is 'To Approve', when time off request is confirmed by user." +
|
||||
"\nThe status is 'Refused', when time off request is refused by manager." +
|
||||
@@ -113,6 +111,7 @@ class HolidaysRequest(models.Model):
|
||||
payslip_status = fields.Boolean('Reported in last payslips', help='Green this button when the time off has been taken into account in the payslip.')
|
||||
report_note = fields.Text('HR Comments')
|
||||
user_id = fields.Many2one('res.users', string='User', related='employee_id.user_id', related_sudo=True, compute_sudo=True, store=True, default=lambda self: self.env.uid, readonly=True)
|
||||
manager_id = fields.Many2one('hr.employee')
|
||||
# leave type configuration
|
||||
holiday_status_id = fields.Many2one(
|
||||
"hr.leave.type", string="Time Off Type", required=True, readonly=True,
|
||||
@@ -123,7 +122,6 @@ class HolidaysRequest(models.Model):
|
||||
employee_id = fields.Many2one(
|
||||
'hr.employee', string='Employee', index=True, readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]}, default=_default_employee, tracking=True)
|
||||
manager_id = fields.Many2one('hr.employee', string='Manager', readonly=True)
|
||||
department_id = fields.Many2one(
|
||||
'hr.department', string='Department', readonly=True,
|
||||
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
|
||||
@@ -263,6 +261,7 @@ class HolidaysRequest(models.Model):
|
||||
self.request_unit_half = False
|
||||
self.request_unit_hours = False
|
||||
self.request_unit_custom = False
|
||||
self.state = 'confirm' if self.validation_type != 'no_validation' else 'draft'
|
||||
|
||||
@api.onchange('user_id')
|
||||
def _onchange_user_id(self):
|
||||
@@ -472,8 +471,7 @@ class HolidaysRequest(models.Model):
|
||||
if holiday.holiday_type != 'employee' or not holiday.employee_id or holiday.holiday_status_id.allocation_type == 'no':
|
||||
continue
|
||||
leave_days = holiday.holiday_status_id.get_days(holiday.employee_id.id)[holiday.holiday_status_id.id]
|
||||
if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \
|
||||
float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
|
||||
if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
|
||||
raise ValidationError(_('The number of remaining time off is not sufficient for this time off type.\n'
|
||||
'Please also check the time off waiting for validation.'))
|
||||
|
||||
@@ -555,32 +553,59 @@ class HolidaysRequest(models.Model):
|
||||
_('You can take %s until %s') % (
|
||||
leave.holiday_status_id.display_name, leave.holiday_status_id.validity_stop))
|
||||
|
||||
def _check_double_validation_rules(self, employee, state):
|
||||
if self.user_has_groups('hr_holidays.group_hr_holidays_manager'):
|
||||
return
|
||||
|
||||
if state == 'validate1':
|
||||
if employee.leave_manager_id != self.env.user:
|
||||
raise AccessError(_('You cannot first approve a leave for %s, because you are not his leave manager' % (employee.name,)))
|
||||
elif state == 'validate' and not self.user_has_groups('hr_holidays.group_hr_holidays_user'):
|
||||
# Is probably handled via ir.rule
|
||||
raise AccessError(_('You don\'t have the rights to apply second approval on a leave request'))
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
""" Override to avoid automatic logging of creation """
|
||||
employee_id = values.get('employee_id', False)
|
||||
leave_type_id = values.get('holiday_status_id')
|
||||
leave_type = self.env['hr.leave.type'].browse(leave_type_id)
|
||||
if leave_type.validation_type == 'no_validation':
|
||||
values.update({'state': 'confirm'})
|
||||
if not self._context.get('leave_fast_create'):
|
||||
employee_id = values.get('employee_id', False)
|
||||
leave_type_id = values.get('holiday_status_id')
|
||||
leave_type = self.env['hr.leave.type'].browse(leave_type_id)
|
||||
# Handle automatic department_id
|
||||
if not values.get('department_id'):
|
||||
values.update({'department_id': self.env['hr.employee'].browse(employee_id).department_id.id})
|
||||
|
||||
# Handle no_validation
|
||||
if leave_type.validation_type == 'no_validation':
|
||||
values.update({'state': 'confirm'})
|
||||
|
||||
# Handle double validation
|
||||
if leave_type.validation_type == 'both':
|
||||
self._check_double_validation_rules(employee_id, values.get('state', False))
|
||||
|
||||
if not values.get('department_id'):
|
||||
values.update({'department_id': self.env['hr.employee'].browse(employee_id).department_id.id})
|
||||
holiday = super(HolidaysRequest, self.with_context(mail_create_nosubscribe=True)).create(values)
|
||||
if not self._context.get('leave_fast_create'):
|
||||
holiday.add_follower(employee_id)
|
||||
if holiday.validation_type == 'hr':
|
||||
holiday.message_subscribe(partner_ids=(holiday.employee_id.parent_id.user_id.partner_id | holiday.employee_id.leave_manager_id.partner_id).ids)
|
||||
# FIXME remove these, as they should not be needed
|
||||
if employee_id:
|
||||
holiday._sync_employee_details()
|
||||
if 'number_of_days' not in values and ('date_from' in values or 'date_to' in values):
|
||||
holiday._onchange_leave_dates()
|
||||
|
||||
# Everything that is done here must be done using sudo because we might
|
||||
# have different create and write rights
|
||||
# eg : holidays_user can create a leave request with validation_type = 'manager' for someone else
|
||||
# but they can only write on it if they are leave_manager_id
|
||||
holiday_sudo = holiday.sudo()
|
||||
holiday_sudo.add_follower(employee_id)
|
||||
if holiday.validation_type == 'manager':
|
||||
holiday_sudo.message_subscribe(partner_ids=holiday.employee_id.leave_manager_id.partner_id.ids)
|
||||
if leave_type.validation_type == 'no_validation':
|
||||
holiday.sudo().action_validate()
|
||||
holiday.message_subscribe(partner_ids=[holiday._get_responsible_for_approval().partner_id.id])
|
||||
holiday.sudo().message_post(body=_("The time off has been automatically approved"), subtype="mt_comment") # Message from OdooBot (sudo)
|
||||
# Automatic validation should be done in sudo, because user might not have the rights to do it by himself
|
||||
holiday_sudo.action_validate()
|
||||
holiday_sudo.message_subscribe(partner_ids=[holiday._get_responsible_for_approval().partner_id.id])
|
||||
holiday_sudo.message_post(body=_("The time off has been automatically approved"), subtype="mt_comment") # Message from OdooBot (sudo)
|
||||
elif not self._context.get('import_file'):
|
||||
holiday.activity_update()
|
||||
holiday_sudo.activity_update()
|
||||
return holiday
|
||||
|
||||
def _read_from_database(self, field_names, inherited_field_names=[]):
|
||||
@@ -609,6 +634,8 @@ class HolidaysRequest(models.Model):
|
||||
employee_id = values.get('employee_id', False)
|
||||
if not self.env.context.get('leave_fast_create') and values.get('state'):
|
||||
self._check_approval_update(values['state'])
|
||||
if any(holiday.validation_type == 'both' for holiday in self):
|
||||
self._check_double_validation_rules(self.env['hr.employee'].browse(values.get('employee_id', self.employee_id.id)), values['state'])
|
||||
result = super(HolidaysRequest, self).write(values)
|
||||
if not self.env.context.get('leave_fast_create'):
|
||||
for holiday in self:
|
||||
@@ -652,7 +679,7 @@ class HolidaysRequest(models.Model):
|
||||
'calendar_id': leave.employee_id.resource_calendar_id.id,
|
||||
'time_type': leave.holiday_status_id.time_type,
|
||||
})
|
||||
return self.env['resource.calendar.leaves'].create(vals_list)
|
||||
return self.env['resource.calendar.leaves'].sudo().create(vals_list)
|
||||
|
||||
def _remove_resource_leave(self):
|
||||
""" This method will create entry in resource calendar time off object at the time of holidays cancel/removed """
|
||||
@@ -737,6 +764,14 @@ class HolidaysRequest(models.Model):
|
||||
|
||||
current_employee = self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)
|
||||
self.filtered(lambda hol: hol.validation_type == 'both').write({'state': 'validate1', 'first_approver_id': current_employee.id})
|
||||
|
||||
|
||||
# Post a second message, more verbose than the tracking message
|
||||
for holiday in self.filtered(lambda holiday: holiday.employee_id.user_id):
|
||||
holiday.message_post(
|
||||
body=_('Your %s planned on %s has been accepted' % (holiday.holiday_status_id.display_name, holiday.date_from)),
|
||||
partner_ids=holiday.employee_id.user_id.partner_id.ids)
|
||||
|
||||
self.filtered(lambda hol: not hol.validation_type == 'both').action_validate()
|
||||
if not self.env.context.get('leave_fast_create'):
|
||||
self.activity_update()
|
||||
@@ -795,6 +830,13 @@ class HolidaysRequest(models.Model):
|
||||
holiday.meeting_id.unlink()
|
||||
# If a category that created several holidays, cancel all related
|
||||
holiday.linked_request_ids.action_refuse()
|
||||
|
||||
# Post a second message, more verbose than the tracking message
|
||||
if holiday.employee_id.user_id:
|
||||
holiday.message_post(
|
||||
body=_('Your %s planned on %s has been refused' % (holiday.holiday_status_id.display_name, holiday.date_from)),
|
||||
partner_ids=holiday.employee_id.user_id.partner_id.ids)
|
||||
|
||||
self._remove_resource_leave()
|
||||
self.activity_update()
|
||||
return True
|
||||
@@ -826,39 +868,23 @@ class HolidaysRequest(models.Model):
|
||||
raise UserError(_('Only a Leave Manager can approve its own requests.'))
|
||||
|
||||
if (state == 'validate1' and val_type == 'both') or (state == 'validate' and val_type == 'manager') and holiday.holiday_type == 'employee':
|
||||
manager = holiday.employee_id.parent_id or holiday.employee_id.department_id.manager_id
|
||||
team_leader = holiday.employee_id.leave_manager_id
|
||||
error = False
|
||||
|
||||
if not manager and not team_leader:
|
||||
error = not is_officer
|
||||
else:
|
||||
error = (not (manager and manager == current_employee) and not (team_leader and team_leader == self.env.user))
|
||||
|
||||
if error:
|
||||
if not is_officer and self.env.user != holiday.employee_id.leave_manager_id:
|
||||
raise UserError(_('You must be either %s\'s manager or Leave manager to approve this leave') % (holiday.employee_id.name))
|
||||
|
||||
if state == 'validate' and val_type == 'both':
|
||||
raise UserError(_('Only an Leave Manager can apply the second approval on leave requests.'))
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Activity methods
|
||||
# ------------------------------------------------------------
|
||||
|
||||
def _get_responsible_for_approval(self):
|
||||
self.ensure_one()
|
||||
responsible = self.env['res.users']
|
||||
responsible = self.env['res.users'].browse(SUPERUSER_ID)
|
||||
|
||||
if self.validation_type == 'hr' or (self.validation_type == 'both' and self.state == 'validate1'):
|
||||
if self.validation_type == 'manager' or (self.validation_type == 'both' and self.state == 'confirm'):
|
||||
if self.employee_id.leave_manager_id:
|
||||
responsible = self.employee_id.leave_manager_id
|
||||
elif self.validation_type == 'hr' or (self.validation_type == 'both' and self.state == 'validate1'):
|
||||
if self.holiday_status_id.responsible_id:
|
||||
responsible = self.holiday_status_id.responsible_id
|
||||
elif self.state == 'confirm' or (self.state == 'validate' and self.validation_type == 'no_validation'):
|
||||
if self.employee_id.leave_manager_id and self.employee_id.leave_manager_id.has_group('hr_holidays.group_hr_holidays_team_leader'):
|
||||
responsible = self.employee_id.leave_manager_id
|
||||
elif self.employee_id.parent_id.user_id and self.employee_id.parent_id.user_id.has_group('hr_holidays.group_hr_holidays_team_leader'):
|
||||
responsible = self.employee_id.parent_id.user_id
|
||||
elif self.department_id.manager_id.user_id:
|
||||
responsible = self.department_id.manager_id.user_id
|
||||
|
||||
return responsible
|
||||
|
||||
@@ -912,7 +938,7 @@ class HolidaysRequest(models.Model):
|
||||
ref_action = self._notify_get_action_link('controller', controller='/leave/refuse')
|
||||
hr_actions += [{'url': ref_action, 'title': _('Refuse')}]
|
||||
|
||||
holiday_user_group_id = self.env.ref('hr_holidays.group_hr_holidays_team_leader').id
|
||||
holiday_user_group_id = self.env.ref('hr_holidays.group_hr_holidays_user').id
|
||||
new_group = (
|
||||
'group_hr_holidays_user', lambda pdata: pdata['type'] == 'user' and holiday_user_group_id in pdata['groups'], {
|
||||
'actions': hr_actions,
|
||||
|
||||
@@ -20,7 +20,12 @@ _logger = logging.getLogger(__name__)
|
||||
class HolidaysType(models.Model):
|
||||
_name = "hr.leave.type"
|
||||
_description = "Time Off Type"
|
||||
_order = "sequence, id"
|
||||
|
||||
@api.model
|
||||
def _model_sorting_key(self, leave_type):
|
||||
remaining = leave_type.virtual_remaining_leaves > 0
|
||||
taken = leave_type.leaves_taken > 0
|
||||
return leave_type.allocation_type == 'fixed' and remaining, leave_type.allocation_type == 'fixed_allocation' and remaining, taken
|
||||
|
||||
name = fields.Char('Time Off Type', required=True, translate=True)
|
||||
code = fields.Char('Code')
|
||||
@@ -63,9 +68,9 @@ class HolidaysType(models.Model):
|
||||
group_days_leave = fields.Float(
|
||||
compute='_compute_group_days_leave', string='Group Time Off')
|
||||
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
|
||||
responsible_id = fields.Many2one('res.users', 'Responsible', domain=lambda self: [('groups_id', 'in', self.env.ref('hr_holidays.group_hr_holidays_user').id)],
|
||||
help="This user will be responsible for approving this type of times off"
|
||||
"This is only used when validation is 'hr' or 'both'",)
|
||||
responsible_id = fields.Many2one('res.users', 'Responsible',
|
||||
help="This user will be responsible for approving this type of times off"
|
||||
"This is only used when validation is 'hr' or 'both'",)
|
||||
validation_type = fields.Selection([
|
||||
('no_validation', 'No Validation'),
|
||||
('hr', 'Time Off Officer'),
|
||||
@@ -198,16 +203,14 @@ class HolidaysType(models.Model):
|
||||
|
||||
@api.model
|
||||
def get_days_all_request(self):
|
||||
employee_id = self._get_contextual_employee_id()
|
||||
|
||||
leaves_type = self.search([])
|
||||
leaves = leaves_type.get_days(employee_id)
|
||||
leave_id_name = dict(zip(leaves_type.ids, leaves_type.mapped('name')))
|
||||
leave_id_allocation_type = dict(zip(leaves_type.ids, leaves_type.mapped('allocation_type')))
|
||||
result = [(leave_id_name[leave_id], {key: round(value, 2) for (key, value) in leave.items()}, leave_id_allocation_type[leave_id]) for leave_id, leave in leaves.items() if leave['virtual_remaining_leaves'] or leave['max_leaves']]
|
||||
|
||||
sort_key = lambda l: (l[2] == 'fixed', l[2] == 'fixed_allocation', l[1]['virtual_remaining_leaves'])
|
||||
return sorted(result, key=sort_key, reverse=True)
|
||||
leave_types = sorted(self.search([]).filtered(lambda x: x.virtual_remaining_leaves or x.max_leaves), key=self._model_sorting_key, reverse=True)
|
||||
return [(lt.name, {
|
||||
'remaining_leaves': lt.remaining_leaves,
|
||||
'virtual_remaining_leaves': lt.virtual_remaining_leaves,
|
||||
'max_leaves': lt.max_leaves,
|
||||
'leaves_taken': lt.leaves_taken,
|
||||
}, lt.allocation_type)
|
||||
for lt in leave_types]
|
||||
|
||||
def _get_contextual_employee_id(self):
|
||||
if 'employee_id' in self._context:
|
||||
@@ -298,8 +301,8 @@ class HolidaysType(models.Model):
|
||||
leave_ids = super(HolidaysType, self)._search(args, offset=offset, limit=limit, order=order, count=count, access_rights_uid=access_rights_uid)
|
||||
if not count and not order and employee_id:
|
||||
leaves = self.browse(leave_ids)
|
||||
sort_key = lambda l: (l.allocation_type in ['fixed', 'fixed_allocation'], l.virtual_remaining_leaves)
|
||||
return leaves.sorted(key=sort_key, reverse=True).ids
|
||||
|
||||
return leaves.sorted(key=self._model_sorting_key, reverse=True).ids
|
||||
return leave_ids
|
||||
|
||||
def action_see_days_allocated(self):
|
||||
|
||||
@@ -5,16 +5,10 @@
|
||||
<field name="sequence">10</field>
|
||||
</record>
|
||||
|
||||
<record id="group_hr_holidays_team_leader" model="res.groups">
|
||||
<field name="name">Team Approver</field>
|
||||
<field name="category_id" ref="base.module_category_human_resources_time_off"/>
|
||||
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_hr_holidays_user" model="res.groups">
|
||||
<field name="name">All Approver</field>
|
||||
<field name="category_id" ref="base.module_category_human_resources_time_off"/>
|
||||
<field name="implied_ids" eval="[(4, ref('group_hr_holidays_team_leader'))]"/>
|
||||
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_hr_holidays_manager" model="res.groups">
|
||||
@@ -29,7 +23,7 @@
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_employee" model="ir.rule">
|
||||
<field name="name">Time Off: employee: read all</field>
|
||||
<field name="name">Time Off base.group_user read</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
@@ -39,35 +33,53 @@
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_employee_update" model="ir.rule">
|
||||
<field name="name">Time Off: employee: create/write/unlink not validated own</field>
|
||||
<field name="name">Time Off base.group_user create/write</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[('employee_id.user_id','=',user.id), ('state', 'in', ['draft', 'confirm', 'cancel', 'refuse']), ('holiday_type', '=', 'employee')]</field>
|
||||
<field name="domain_force">[
|
||||
('holiday_type', '=', 'employee'),
|
||||
'|',
|
||||
'&',
|
||||
('employee_id.user_id', '=', user.id),
|
||||
('state', 'not in', ['validate', 'validate1']),
|
||||
'&',
|
||||
('validation_type', 'in', ['manager', 'both', 'no_validation']),
|
||||
('employee_id.leave_manager_id', '=', user.id),
|
||||
]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4,ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_team_leader_update" model="ir.rule">
|
||||
<field name="name">Time Off: approver: write on employee's time off in his team</field>
|
||||
<record id="hr_leave_rule_employee_unlink" model="ir.rule">
|
||||
<field name="name">Time Off base.group_user unlink</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">['&', ('holiday_type', '=', 'employee'), '|', ('employee_id.leave_manager_id', '=' , user.id), ('employee_id.parent_id.user_id', '=' , user.id)]</field>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id), ('state', '=', 'draft')]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_team_leader'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_officer_update" model="ir.rule">
|
||||
<field name="name">Time Off: see all time off: create/write/unlink own + managed employee + without department + same or managed department</field>
|
||||
<field name="name">Time Off All Approver create/write</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">['|',
|
||||
'|', ('employee_id.user_id', '=', user.id), ('employee_id.parent_id.user_id', '=', user.id),
|
||||
'|', '|', ('department_id', '=', False), ('department_id.member_ids.user_id', 'in', [user.id]), ('department_id.manager_id.user_id', '=', user.id)]</field>
|
||||
<field name="domain_force">[
|
||||
('holiday_type', '=', 'employee'),
|
||||
'|',
|
||||
'&',
|
||||
('employee_id.user_id', '=', user.id),
|
||||
('state', '!=', 'validate'),
|
||||
'|',
|
||||
('employee_id.user_id', '!=', user.id),
|
||||
('employee_id.user_id', '=', False)
|
||||
]</field>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_rule_manager" model="ir.rule">
|
||||
<field name="name">Time Off: administrator: no limit</field>
|
||||
<field name="name">Time Off Administrator</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_hr_holidays_manager'))]"/>
|
||||
@@ -83,7 +95,11 @@
|
||||
<record id="hr_leave_allocation_rule_employee" model="ir.rule">
|
||||
<field name="name">Allocations: employee: read own</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">[('employee_id.user_id', '=', user.id)]</field>
|
||||
<field name="domain_force">[
|
||||
'|',
|
||||
('employee_id.leave_manager_id', '=', user.id),
|
||||
('employee_id.user_id', '=', user.id)
|
||||
]</field>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
@@ -124,21 +140,22 @@
|
||||
<field name="groups" eval="[(4, ref('group_hr_holidays_manager'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_allocation_rule_team_leader" model="ir.rule">
|
||||
<field name="name">Allocations: Team Leader: read employee's allocations in his team</field>
|
||||
<field name="model_id" ref="model_hr_leave_allocation"/>
|
||||
<field name="domain_force">['|', ('employee_id.leave_manager_id', '=' , user.id), ('employee_id.parent_id.user_id', '=' , user.id)]</field>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_team_leader'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="resource_leaves_team_leader" model="ir.rule">
|
||||
<record id="resource_leaves_base_user" model="ir.rule">
|
||||
<field name="name">Time Off Resources: Approver</field>
|
||||
<field name="model_id" ref="model_resource_calendar_leaves"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_team_leader'))]"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- FIXME RLi Maybe this should be restricted somewhat -->
|
||||
<record id="resource_leaves_holidays_user" model="ir.rule">
|
||||
<field name="name">Time Off Resources: All Approver</field>
|
||||
<field name="model_id" ref="model_resource_calendar_leaves"/>
|
||||
<field name="domain_force">[(1,'=',1)]</field>
|
||||
<field name="groups" eval="[(4, ref('hr_holidays.group_hr_holidays_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_holidays_status_rule_multi_company" model="ir.rule">
|
||||
|
||||
@@ -3,6 +3,7 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
|
||||
var core = require('web.core');
|
||||
var CalendarController = require("web.CalendarController");
|
||||
var CalendarRenderer = require("web.CalendarRenderer");
|
||||
var CalendarView = require("web.CalendarView");
|
||||
var viewRegistry = require('web.view_registry');
|
||||
|
||||
@@ -12,36 +13,10 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
|
||||
var TimeOffCalendarController = CalendarController.extend({
|
||||
events: _.extend({}, CalendarController.prototype.events, {
|
||||
'click .o_header_calendar_button_prev': '_onPrev',
|
||||
'click .o_header_calendar_button_next': '_onNext',
|
||||
'click .btn-time-off': '_onNewTimeOff',
|
||||
'click .btn-allocation': '_onNewAllocation',
|
||||
}),
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self.$el.find('.o_calendar_sidebar_container').remove();
|
||||
self._renderSummaryTimeOff();
|
||||
self.$(".o_calendar_widget").fullCalendar('option', 'contentHeight', 500);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Override to add correct date in header of calendar
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
update: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self._updateSummaryTimeOff();
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -54,10 +29,12 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
*/
|
||||
|
||||
renderButtons: function ($node) {
|
||||
this.$buttons = $(QWeb.render('hr_holidays.dashboard.calendar.button', {
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
$(QWeb.render('hr_holidays.dashboard.calendar.button', {
|
||||
time_off: _t('New Time Off Request'),
|
||||
request: _t('New Allocation Request'),
|
||||
}));
|
||||
})).appendTo(this.$buttons);
|
||||
|
||||
if ($node) {
|
||||
this.$buttons.appendTo($node);
|
||||
@@ -66,79 +43,6 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a header for calendar with previous and next month button.
|
||||
* Add month and year on the header
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_renderCalendarHeader: function () {
|
||||
this.$el.find('.fc-week-number').remove();
|
||||
|
||||
if (!this.$('#header_calendar_leaves').length) {
|
||||
var current_month = this.model.data.target_date.format('MMMM YYYY');
|
||||
var header = $(QWeb.render('hr_holidays.dashboard.calendar.header', {
|
||||
current_month: current_month,
|
||||
}));
|
||||
|
||||
this.$el.find('.fc-widget-header').find('thead').prepend(header);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a summary of all time off and requests allocations
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_renderSummaryTimeOff: function () {
|
||||
var leave_state = '<div class="o_form_view"><div class="o_form_sheet_bg"><div class="o_form_sheet"><div id="counter_leaves" class="row">';
|
||||
leave_state += '</div></div></div></div>';
|
||||
this.$el.find('.o_calendar_container').before(
|
||||
$(leave_state)
|
||||
);
|
||||
|
||||
this._updateSummaryTimeOff();
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a summary of all time off and requests allocations
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_updateSummaryTimeOff: function () {
|
||||
var self = this;
|
||||
|
||||
this._renderCalendarHeader();
|
||||
|
||||
return this._rpc({
|
||||
model: 'hr.leave.type',
|
||||
method: 'get_days_all_request',
|
||||
context: this.context,
|
||||
})
|
||||
.then(function (leaves) {
|
||||
$('#counter_leaves').children().remove();
|
||||
for (var leave in leaves){
|
||||
var leave_box = $('<div class="col text-center border-right"><h1 class="text-nowrap"></h1><h3></h3></div>');
|
||||
var content = leaves[leave][1];
|
||||
var leave_count = leave_box.find('h1');
|
||||
leave_box.append(leave_count.text(
|
||||
leaves[leave][2] !== 'no' ? content.virtual_remaining_leaves + " / " + content.max_leaves : -content.virtual_remaining_leaves
|
||||
));
|
||||
var leave_name = leave_box.find('h3');
|
||||
leave_name.text(leaves[leave][0]);
|
||||
leave_box.append(leave_name);
|
||||
$('#counter_leaves').append(leave_box);
|
||||
}
|
||||
$('#counter_leaves').children().last().removeClass('border-right');
|
||||
|
||||
self.$el.find('.o_calendar_container').appendTo(self.$el.find('.o_form_sheet'));
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -177,11 +81,30 @@ odoo.define('hr_holidays.dashboard.view_custo', function(require) {
|
||||
});
|
||||
},
|
||||
});
|
||||
var TimeOffCalendarRenderer = CalendarRenderer.extend({
|
||||
_render: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
return self._rpc({
|
||||
model: 'hr.leave.type',
|
||||
method: 'get_days_all_request',
|
||||
context: self.context,
|
||||
});
|
||||
}).then(function (result) {
|
||||
self.$el.parent().find('.o_timeoff_container').remove();
|
||||
var elem = QWeb.render('hr_holidays.dashboard_calendar_header', {
|
||||
timeoffs: result,
|
||||
});
|
||||
self.$el.before(elem);
|
||||
});
|
||||
},
|
||||
});
|
||||
var TimeOffCalendarView = CalendarView.extend({
|
||||
config: _.extend({}, CalendarView.prototype.config, {
|
||||
Controller: TimeOffCalendarController,
|
||||
Renderer: TimeOffCalendarRenderer,
|
||||
}),
|
||||
});
|
||||
|
||||
viewRegistry.add('time_off_calendar', TimeOffCalendarView);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
.o_content {
|
||||
.o_timeoff_card {
|
||||
border-right: #adb5bd solid 2px;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.o_timeoff_card_last {
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
.o_timeoff_big {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
.o_timeoff_purple {
|
||||
color: $o-enterprise-color;
|
||||
}
|
||||
|
||||
.o_timeoff_green {
|
||||
color: $o-enterprise-primary-color;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="hr_holidays.dashboard.calendar.header">
|
||||
<tr id="header_calendar_leaves">
|
||||
<th colspan="7">
|
||||
<button class="btn o_header_calendar_button_prev float-left" type="button">
|
||||
<span class="fa fa-arrow-left"/>
|
||||
</button>
|
||||
<button class="btn o_header_calendar_button_next float-right" type="button">
|
||||
<span class="fa fa-arrow-right"/>
|
||||
</button>
|
||||
<h2 class="o_header_calendar_month"><t t-esc="current_month"/></h2>
|
||||
</th>
|
||||
</tr>
|
||||
<t t-name="hr_holidays.dashboard_calendar_header">
|
||||
<div class="o_timeoff_container d-flex">
|
||||
<div t-foreach="timeoffs" t-as="timeoff" t-attf-class="o_timeoff_card flex-grow-1 d-flex flex-column {{ timeoff_last ? 'o_timeoff_card_last' : '' }}">
|
||||
<t t-set="need_allocation" t-value="timeoff[2] !== 'no'"/>
|
||||
<t t-set="cl" t-value="'text-muted'"/>
|
||||
|
||||
<t t-if="need_allocation && timeoff[1]['virtual_remaining_leaves'] > 0">
|
||||
<t t-set="cl" t-value="'o_timeoff_green'"/>
|
||||
</t>
|
||||
|
||||
<div>
|
||||
<t t-if="need_allocation">
|
||||
<span t-esc="timeoff[1]['leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> / <span t-esc="timeoff[1]['max_leaves']"/> Days
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-esc="timeoff[1]['leaves_taken']" class="o_timeoff_big o_timeoff_purple"/> Days
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<span t-esc="timeoff[0]" class="o_timeoff_name"/>
|
||||
|
||||
<span t-if="need_allocation"><span t-attf-class="mr-1 font-weight-bold {{ cl }}" t-esc="timeoff[1]['remaining_leaves']"/><span class="text-muted">remaining</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="hr_holidays.dashboard.calendar.button">
|
||||
|
||||
@@ -20,12 +20,6 @@ class TestHrHolidaysBase(common.TransactionCase):
|
||||
self.user_employee = mail_new_test_user(self.env, login='david', groups='base.group_user')
|
||||
self.user_employee_id = self.user_employee.id
|
||||
|
||||
self.user_hrmanager_2 = mail_new_test_user(self.env, login='florence', groups='base.group_user,hr_holidays.group_hr_holidays_manager')
|
||||
self.user_hrmanager_2_id = self.user_hrmanager_2.id
|
||||
|
||||
self.user_team_leader = mail_new_test_user(self.env, login='arthur', groups='base.group_user,hr_holidays.group_hr_holidays_team_leader')
|
||||
self.user_team_leader_id = self.user_team_leader.id
|
||||
|
||||
# Hr Data
|
||||
Department = self.env['hr.department'].with_context(tracking_disable=True)
|
||||
|
||||
@@ -54,13 +48,8 @@ class TestHrHolidaysBase(common.TransactionCase):
|
||||
'name': 'Bastien HrManager',
|
||||
'user_id': self.user_hrmanager_id,
|
||||
'department_id': self.hr_dept.id,
|
||||
'parent_id': self.employee_hruser_id,
|
||||
})
|
||||
self.employee_hrmanager_id = self.employee_hrmanager.id
|
||||
|
||||
self.employee_hrmanager_2_id = self.env['hr.employee'].create({
|
||||
'name': 'Florence HrManager',
|
||||
'user_id': self.user_hrmanager_2_id,
|
||||
'parent_id': self.employee_hrmanager_id,
|
||||
}).id
|
||||
|
||||
self.rd_dept.write({'manager_id': self.employee_hruser_id})
|
||||
|
||||
@@ -6,13 +6,12 @@ from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import tests
|
||||
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase
|
||||
from odoo.exceptions import AccessError, ValidationError, UserError
|
||||
from odoo.exceptions import AccessError, UserError
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
@tests.tagged('access_rights', 'post_install', '-at_install')
|
||||
class TestLeavesRights(TestHrHolidaysBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestLeavesRights, self).setUp()
|
||||
self.leave_type = self.env['hr.leave.type'].create({
|
||||
@@ -34,22 +33,409 @@ class TestLeavesRights(TestHrHolidaysBase):
|
||||
'number_of_days': 1,
|
||||
})
|
||||
|
||||
self.lt_no_validation = self.env['hr.leave.type'].create({
|
||||
'name': 'Validation = no_validation',
|
||||
'validation_type': 'hr',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
self.lt_validation_hr = self.env['hr.leave.type'].create({
|
||||
'name': 'Validation = HR',
|
||||
'validation_type': 'hr',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
self.lt_validation_manager = self.env['hr.leave.type'].create({
|
||||
'name': 'Validation = manager',
|
||||
'validation_type': 'hr',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
self.lt_validation_both = self.env['hr.leave.type'].create({
|
||||
'name': 'Validation = both',
|
||||
'validation_type': 'hr',
|
||||
'allocation_type': 'no',
|
||||
'validity_start': False,
|
||||
})
|
||||
|
||||
self.draft_status = [
|
||||
self.lt_validation_hr,
|
||||
self.lt_validation_manager,
|
||||
self.lt_validation_both
|
||||
]
|
||||
|
||||
self.confirm_status = [
|
||||
self.lt_no_validation,
|
||||
self.lt_validation_hr,
|
||||
self.lt_validation_manager,
|
||||
self.lt_validation_both
|
||||
]
|
||||
|
||||
def request_leave(self, user_id, date_from, number_of_days, values=None):
|
||||
values = dict(values or {}, **{
|
||||
'date_from': date_from,
|
||||
'date_to': date_from + relativedelta(days=number_of_days),
|
||||
'number_of_days': number_of_days,
|
||||
})
|
||||
return self.env['hr.leave'].with_user(user_id).create(values)
|
||||
|
||||
|
||||
@tests.tagged('access_rights', 'access_rights_states')
|
||||
class TestAcessRightsStates(TestLeavesRights):
|
||||
# ******************************************************
|
||||
# Action draft
|
||||
# ******************************************************
|
||||
|
||||
def test_draft_status(self):
|
||||
"""
|
||||
We should only be able to draft a leave that is
|
||||
in confirm or refuse state
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Ranoi',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.action_draft()
|
||||
|
||||
values = {
|
||||
'name': 'Ranoi',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
'state': 'draft'
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=20 + i), 1, values)
|
||||
with self.assertRaises(UserError):
|
||||
leave.action_draft()
|
||||
|
||||
def test_base_user_draft_his_leave(self):
|
||||
"""
|
||||
Should be able to draft his own leave
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_employee.id).action_draft()
|
||||
|
||||
def test_base_user_draft_other_employee_leave(self):
|
||||
"""
|
||||
Should not be able to draft the leave of someone else
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
with self.assertRaises(UserError):
|
||||
leave.with_user(self.user_employee.id).action_draft()
|
||||
|
||||
def test_base_user_draft_other_employee_leave_and_is_leave_manager_id(self):
|
||||
"""
|
||||
Should not be able to draft the leave of someone else
|
||||
even when being the leave manager id for this person
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
self.employee_hruser.write({'leave_manager_id': self.user_employee.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
with self.assertRaises(UserError):
|
||||
leave.with_user(self.user_employee.id).action_draft()
|
||||
|
||||
def test_base_user_draft_self_and_is_leave_manager_id(self):
|
||||
"""
|
||||
Should be able to draft his own leave
|
||||
even when being leave manager id
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
self.employee_emp.write({'leave_manager_id': self.user_employee.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_employee.id).action_draft()
|
||||
|
||||
def test_holiday_user_draft_his_leave(self):
|
||||
"""
|
||||
Should be able to draft his own leave
|
||||
whatever the holidays_status_id
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hruser.id).action_draft()
|
||||
|
||||
def test_holiday_user_draft_other_employee_leave(self):
|
||||
"""
|
||||
Should not be able to draft other employee leave
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
with self.assertRaises(UserError):
|
||||
leave.with_user(self.user_hruser.id).action_draft()
|
||||
|
||||
def test_holiday_user_draft_other_employee_leave_and_is_leave_manager_id(self):
|
||||
"""
|
||||
Should not be able to draft other employee leave
|
||||
even if he is the leave manager id
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
self.employee_emp.write({'leave_manager_id': self.user_hruser.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_emp.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
with self.assertRaises(UserError):
|
||||
leave.with_user(self.user_hruser.id).action_draft()
|
||||
|
||||
def test_holiday_user_draft_self_and_is_manager_id(self):
|
||||
"""
|
||||
Should be able to draft his own leave
|
||||
even if he is leave manager id
|
||||
whatever the holiday_status_id
|
||||
"""
|
||||
self.employee_hruser.write({'leave_manager_id': self.user_hruser.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hruser.id).action_draft()
|
||||
|
||||
def test_holiday_manager_draft_his_leave(self):
|
||||
"""
|
||||
The holiday manager should be able to do everything
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hrmanager.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hrmanager.id).action_draft()
|
||||
|
||||
def test_holiday_manager_draft_other_employee_leave(self):
|
||||
"""
|
||||
The holiday manager should be able to do everything
|
||||
"""
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hrmanager.id).action_draft()
|
||||
|
||||
def test_holiday_manager_draft_other_employee_leave_and_is_leave_manager_id(self):
|
||||
"""
|
||||
The holiday manager should be able to do everything
|
||||
"""
|
||||
self.employee_hruser.write({'leave_manager_id': self.user_hrmanager.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hrmanager.id).action_draft()
|
||||
|
||||
def test_holiday_manager_draft_self_and_is_manager_id(self):
|
||||
"""
|
||||
The holiday manager should be able to do everything
|
||||
"""
|
||||
self.employee_hrmanager.write({'leave_manager_id': self.user_hrmanager.id})
|
||||
for i, status in enumerate(self.draft_status):
|
||||
values = {
|
||||
'name': 'Random Leave',
|
||||
'employee_id': self.employee_hrmanager.id,
|
||||
'holiday_status_id': status.id,
|
||||
}
|
||||
leave = self.request_leave(1, datetime.today() + relativedelta(days=5 + i), 1, values)
|
||||
leave.with_user(self.user_hrmanager.id).action_draft()
|
||||
|
||||
@tests.tagged('access_rights', 'access_rights_create')
|
||||
class TestAccessRightsCreate(TestLeavesRights):
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_messaging_by_user(self):
|
||||
""" User may communicate on its own leaves, even if validated """
|
||||
self.employee_leave.with_user(self.user_employee_id).message_post(
|
||||
body='I haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
def test_base_user_create_self(self):
|
||||
""" A simple user can create a leave for himself """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_base_user_create_other(self):
|
||||
""" A simple user cannot create a leave for someone else """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
with self.assertRaises(AccessError):
|
||||
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
self.employee_leave.with_user(self.user_employee_id).message_post(
|
||||
body='I still haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_base_user_create_validate(self):
|
||||
""" A simple user cannot create a leave in validate state """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'state': 'validate',
|
||||
}
|
||||
with self.assertRaises(AccessError):
|
||||
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_base_user_create_batch(self):
|
||||
""" A simple user cannot create a leave in bacth mode (by company, by department, by tag)"""
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'holiday_type': 'company',
|
||||
'mode_company_id': 1,
|
||||
}
|
||||
with self.assertRaises(AccessError):
|
||||
self.request_leave(self.user_employee_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
# hr_holidays.group_hr_holidays_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_user_create_self(self):
|
||||
""" A holidays user can create a leave for himself """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_user_create_other(self):
|
||||
""" A holidays user can create a leave for someone else """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_user_create_validate(self):
|
||||
""" A holidays user can create a leave in validate state but not for himself """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'state': 'validate',
|
||||
}
|
||||
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
values.update(employee_id=self.employee_hruser_id)
|
||||
with self.assertRaises(AccessError):
|
||||
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_user_create_batch(self):
|
||||
""" A holidays user cannot create a leave in bacth mode (by company, by department, by tag)"""
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'holiday_type': 'company',
|
||||
'mode_company_id': 1,
|
||||
}
|
||||
with self.assertRaises(AccessError):
|
||||
self.request_leave(self.user_hruser_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
# hr_holidays.group_hr_holidays_manager
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_manager_create_self(self):
|
||||
""" A holidays manager can create a leave for himself """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_hrmanager_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_manager_create_other(self):
|
||||
""" A holidays manager can create a leave for someone else """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
}
|
||||
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_manager_create_validate(self):
|
||||
""" A holidays manager can? create a leave in validate state even for himself """
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'state': 'validate',
|
||||
}
|
||||
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
values.update(employee_id=self.employee_hruser_id)
|
||||
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_holidays_manager_create_batch(self):
|
||||
""" A holidays manager can create a leave in bacth mode (by company, by department, by tag)"""
|
||||
values = {
|
||||
'name': 'Hol10',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'holiday_type': 'company',
|
||||
'mode_company_id': 1,
|
||||
}
|
||||
self.request_leave(self.user_hrmanager_id, datetime.today() + relativedelta(days=5), 1, values)
|
||||
|
||||
|
||||
@tests.tagged('access_rights', 'access_rights_read')
|
||||
class TestAccessRightsRead(TestLeavesRights):
|
||||
# base.group_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_other(self):
|
||||
@@ -92,19 +478,18 @@ class TestLeavesRights(TestHrHolidaysBase):
|
||||
res = self.employee_leave.read(['name', 'number_of_days', 'state'])
|
||||
self.assertEqual(res[0]['name'], 'Test')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_read_by_user_own_browse(self):
|
||||
""" Users should be able to browse name field of own requests """
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.assertEqual(self.employee_leave.name, 'Test')
|
||||
|
||||
@tests.tagged('access_rights', 'access_rights_write')
|
||||
class TestAccessRightsWrite(TestLeavesRights):
|
||||
# base.group_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_update_hr_by_user(self):
|
||||
def test_leave_update_by_user(self):
|
||||
""" User may update its leave """
|
||||
self.employee_leave.with_user(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_update_hr_by_user_other(self):
|
||||
def test_leave_update_by_user_other(self):
|
||||
""" User cannot update other people leaves """
|
||||
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
@@ -118,10 +503,6 @@ class TestLeavesRights(TestHrHolidaysBase):
|
||||
with self.assertRaises(AccessError):
|
||||
other_leave.with_user(self.user_employee_id).write({'name': 'Crocodile Dundee is my man'})
|
||||
|
||||
# ----------------------------------------
|
||||
# Creation
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_creation_for_other_user(self):
|
||||
""" Employee cannot creates a leave request for another employee """
|
||||
@@ -136,132 +517,52 @@ class TestLeavesRights(TestHrHolidaysBase):
|
||||
'number_of_days': 1,
|
||||
})
|
||||
|
||||
# ----------------------------------------
|
||||
# Reset
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_manager(self):
|
||||
""" Manager resets its own leaves """
|
||||
manager_leave = self.env['hr.leave'].with_user(self.user_hrmanager).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hrmanager.department_id.id,
|
||||
'employee_id': self.employee_hrmanager.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days': 1,
|
||||
})
|
||||
manager_leave.with_user(self.user_hrmanager).action_draft()
|
||||
def test_leave_messaging_by_user(self):
|
||||
""" User may communicate on its own leaves, even if validated """
|
||||
self.employee_leave.with_user(self.user_employee_id).message_post(
|
||||
body='I haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_manager_other(self):
|
||||
""" Manager may reset other leaves """
|
||||
self.employee_leave.with_user(self.user_hrmanager).action_draft()
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_officer(self):
|
||||
""" Officer resets its own leaves """
|
||||
officer_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days': 1,
|
||||
})
|
||||
officer_leave.with_user(self.user_hruser).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_officer_other(self):
|
||||
""" Officer may not reset other leaves """
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_user(self):
|
||||
""" User resets its own leaves """
|
||||
self.employee_leave.with_user(self.user_employee_id).action_draft()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_reset_by_user_other(self):
|
||||
""" User may not reset other leaves """
|
||||
other_leave = self.env['hr.leave'].with_user(self.user_hruser).create({
|
||||
'name': 'Test',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'department_id': self.employee_hruser.department_id.id,
|
||||
'employee_id': self.employee_hruser.id,
|
||||
'date_from': datetime.now(),
|
||||
'date_to': datetime.now() + relativedelta(days=1),
|
||||
'number_of_days': 1,
|
||||
})
|
||||
with self.assertRaises(UserError):
|
||||
other_leave.with_user(self.user_employee_id).action_draft()
|
||||
self.employee_leave.with_user(self.user_employee_id).message_post(
|
||||
body='I still haz messaging',
|
||||
subtype='mail.mt_comment',
|
||||
message_type='comment'
|
||||
)
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: one validation, HR
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_manager(self):
|
||||
""" Manager validates hr-only leaves """
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'validate')
|
||||
# base.group_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_department(self):
|
||||
""" Officer validates hr-only leaves for co-workers """
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'validate')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_no_department(self):
|
||||
""" Officer validates hr-only leaves for workers from no department and with no manager """
|
||||
self.employee_hruser.write({'department_id': False})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_with_manager(self):
|
||||
""" Officer may not validate hr-only leaves for workers from another department that has a manager """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_wo_manager(self):
|
||||
""" Officer may not validate hr-only leaves for workers from another department that has no manager """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_officer_other_department_manager(self):
|
||||
""" Officer validates hr-only leaves for workers from another department that he manages """
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hruser.id})
|
||||
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'validate')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_hr_by_user(self):
|
||||
""" User may not validate any leaves """
|
||||
def test_leave_hr_to_validate_by_user(self):
|
||||
""" User may not validate any leaves in HR mode """
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_employee_id).action_approve()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_employee_id).write({'state': 'validate'})
|
||||
|
||||
# hr_holidays.group_hr_holidays_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validate_by_manager(self):
|
||||
""" Manager (who has no manager) validate its own leaves """
|
||||
def test_leave_hr_to_validate_by_holiday_user(self):
|
||||
""" Manager can validate leaves in HR mode """
|
||||
self.assertEqual(self.employee_leave.state, 'confirm')
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
self.assertEqual(self.employee_leave.state, 'validate')
|
||||
|
||||
# hr_holidays.group_hr_holidays_manager
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_hr_to_validate_by_manager(self):
|
||||
""" Manager validate its own leaves """
|
||||
manager_leave = self.env['hr.leave'].with_user(self.user_hrmanager_id).create({
|
||||
'name': 'Hol manager',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
@@ -274,125 +575,115 @@ class TestLeavesRights(TestHrHolidaysBase):
|
||||
manager_leave.action_approve()
|
||||
self.assertEqual(manager_leave.state, 'validate')
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validate_by_manager_2(self):
|
||||
""" Manager (who has also a manager) validate its own leaves """
|
||||
manager_leave2 = self.env['hr.leave'].with_user(self.user_hrmanager_2_id).create({
|
||||
'name': 'Hol manager2',
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'employee_id': self.employee_hrmanager_2_id,
|
||||
'date_from': (datetime.today() + relativedelta(days=15)),
|
||||
'date_to': (datetime.today() + relativedelta(days=16)),
|
||||
'number_of_days': 1,
|
||||
})
|
||||
self.assertEqual(manager_leave2.state, 'confirm')
|
||||
manager_leave2.action_approve()
|
||||
self.assertEqual(manager_leave2.state, 'validate')
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: one validation, manager
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_manager(self):
|
||||
""" Manager validates manager-only leaves """
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
# base.group_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_department_manager(self):
|
||||
""" Officer validates manager-only leaves for co-workers from department he manages"""
|
||||
def test_leave_manager_to_validate_by_user(self):
|
||||
""" A simple user can validate in manager mode if he is leave_manager_id """
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hruser.id})
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_department_manager_other(self):
|
||||
""" Officer may not validates manager-only leaves for co-workers from department he does not"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_hruser.write({'department_id': self.hr_dept.id})
|
||||
self.employee_leave.sudo().department_id.write({'manager_id': self.employee_hrmanager.id})
|
||||
values = {
|
||||
'name': 'Hol HrUser',
|
||||
'employee_id': self.employee_hruser_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'state': 'confirm',
|
||||
}
|
||||
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=2), 1, values)
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
hr_leave.with_user(self.user_employee_id).action_approve()
|
||||
self.employee_hruser.write({'leave_manager_id': self.user_employee_id})
|
||||
hr_leave.with_user(self.user_employee_id).action_approve()
|
||||
|
||||
# hr_holidays.group_hr_holidays_user
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_manager(self):
|
||||
""" Officer validates manager-only leaves for co-workers that he manages"""
|
||||
def test_leave_manager_to_validate_by_holiday_user(self):
|
||||
""" A holiday user can validate in manager mode """
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_emp.write({'parent_id': self.employee_hruser.id})
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_manager_by_officer_manager_other(self):
|
||||
""" Officer may not validate manager-only leaves for co-workers he does not manage"""
|
||||
self.leave_type.write({'validation_type': 'manager'})
|
||||
self.employee_emp.write({'parent_id': self.employee_hrmanager.id})
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_hruser).write({'state': 'validate'})
|
||||
values = {
|
||||
'name': 'Hol HrUser',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'state': 'confirm',
|
||||
}
|
||||
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=2), 1, values)
|
||||
hr_leave.with_user(self.user_hruser_id).action_approve()
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: double
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_manager(self):
|
||||
""" Manager validates double validation leaves """
|
||||
def test_leave_double_validate(self):
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_approve()
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_validate()
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_officer(self):
|
||||
""" Officer may not validate double validation leaves """
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_hruser).action_validate()
|
||||
|
||||
with self.assertRaises(UserError):
|
||||
self.employee_leave.with_user(self.user_hruser).write({'state': 'validate'})
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_both_by_officer_and_manager(self):
|
||||
""" Officer + Manager complete double validation leaves """
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
self.employee_leave.with_user(self.user_hruser).action_approve()
|
||||
self.employee_leave.with_user(self.user_hrmanager_id).action_validate()
|
||||
|
||||
# ----------------------------------------
|
||||
# Validation: team leader
|
||||
# ----------------------------------------
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_team_leader_other(self):
|
||||
""" Team Leader validates its employee's allocations only"""
|
||||
self.leave_type.write({'allocation_type': 'fixed'})
|
||||
self.env['hr.leave.allocation'].create({
|
||||
values = {
|
||||
'name': 'double HrManager',
|
||||
'employee_id': self.employee_hrmanager_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'employee_id': self.employee_emp.id,
|
||||
'number_of_days': 10,
|
||||
}).action_approve()
|
||||
'state': 'confirm',
|
||||
}
|
||||
self.employee_hrmanager.leave_manager_id = self.env['res.users'].browse(1)
|
||||
hr_leave = self.request_leave(self.user_hruser_id, datetime.now() + relativedelta(days=6), 1, values)
|
||||
hr_user_leave = hr_leave.with_user(self.user_hruser_id)
|
||||
with self.assertRaises(AccessError):
|
||||
self.employee_leave.with_user(self.user_team_leader).action_approve()
|
||||
hr_user_leave.action_approve()
|
||||
with self.assertRaises(AccessError):
|
||||
hr_leave.with_user(self.user_employee_id).action_approve()
|
||||
|
||||
self.employee_hrmanager.leave_manager_id = self.user_hruser
|
||||
hr_leave.with_user(self.user_hruser_id).action_approve()
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
hr_leave.with_user(self.user_employee_id).action_validate()
|
||||
hr_leave.with_user(self.user_hruser_id).action_validate()
|
||||
|
||||
# hr_holidays.group_hr_holidays_manager
|
||||
|
||||
@mute_logger('odoo.models.unlink', 'odoo.addons.mail.models.mail_mail')
|
||||
def test_leave_validation_team_leader(self):
|
||||
""" Team Leader validates its employee's allocations"""
|
||||
self.leave_type.write({'allocation_type': 'fixed'})
|
||||
|
||||
# set the team leader
|
||||
self.employee_emp.leave_manager_id = self.user_team_leader
|
||||
|
||||
self.env['hr.leave.allocation'].create({
|
||||
def test_leave_double_validate_holiday_manager(self):
|
||||
self.leave_type.write({'validation_type': 'both'})
|
||||
values = {
|
||||
'name': 'double HrManager',
|
||||
'employee_id': self.employee_emp_id,
|
||||
'holiday_status_id': self.leave_type.id,
|
||||
'employee_id': self.employee_emp.id,
|
||||
'number_of_days': 10,
|
||||
}).action_approve()
|
||||
self.employee_leave.with_user(self.user_team_leader).action_approve()
|
||||
'state': 'confirm',
|
||||
}
|
||||
hr_leave = self.request_leave(self.user_hrmanager_id, datetime.now() + relativedelta(days=4), 1, values).with_user(self.user_hrmanager_id)
|
||||
hr_leave.action_approve()
|
||||
hr_leave.action_validate()
|
||||
|
||||
# ----------------------------------------
|
||||
# State = Refuse
|
||||
# ----------------------------------------
|
||||
|
||||
# base.group_user
|
||||
|
||||
# hr_holidays.group_hr_holidays_user
|
||||
|
||||
# TODO Can refuse
|
||||
|
||||
# hr_holidays.group_hr_holidays_manager
|
||||
|
||||
# TODO Can refuse
|
||||
|
||||
# ----------------------------------------
|
||||
# State = Cancel
|
||||
# ----------------------------------------
|
||||
|
||||
# base.group_user
|
||||
|
||||
# TODO Can Cancel if start_date in the future
|
||||
|
||||
# hr_holidays.group_hr_holidays_user
|
||||
|
||||
# TODO Can Cancel if not in validate
|
||||
|
||||
# hr_holidays.group_hr_holidays_manager
|
||||
|
||||
# TODO Can always cancel with great powers comes great responbilities
|
||||
|
||||
|
||||
class TestMultiCompany(TestHrHolidaysBase):
|
||||
@@ -426,7 +717,7 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
employee_leave = self.employee_leave.with_user(self.user_employee)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave.name
|
||||
employee_leave.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave.action_approve()
|
||||
@@ -436,7 +727,7 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
employee_leave_hruser = self.employee_leave.with_user(self.user_hruser)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave_hruser.name
|
||||
employee_leave_hruser.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave_hruser.action_approve()
|
||||
@@ -446,7 +737,7 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
employee_leave_hrmanager = self.employee_leave.with_user(self.user_hrmanager)
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
name = employee_leave_hrmanager.name
|
||||
employee_leave_hrmanager.name
|
||||
|
||||
with self.assertRaises(AccessError):
|
||||
employee_leave_hrmanager.action_approve()
|
||||
@@ -456,7 +747,7 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave = self.employee_leave.with_user(self.user_employee)
|
||||
|
||||
name = employee_leave.name
|
||||
employee_leave.name
|
||||
with self.assertRaises(UserError):
|
||||
employee_leave.action_approve()
|
||||
self.assertEqual(employee_leave.state, 'confirm')
|
||||
@@ -466,7 +757,7 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave_hruser = self.employee_leave.with_user(self.user_hruser)
|
||||
|
||||
name = employee_leave_hruser.name
|
||||
employee_leave_hruser.name
|
||||
employee_leave_hruser.action_approve()
|
||||
self.assertEqual(employee_leave_hruser.state, 'validate')
|
||||
|
||||
@@ -475,6 +766,6 @@ class TestMultiCompany(TestHrHolidaysBase):
|
||||
self.leave_type.write({'company_id': False})
|
||||
employee_leave_hrmanager = self.employee_leave.with_user(self.user_hrmanager)
|
||||
|
||||
name = employee_leave_hrmanager.name
|
||||
employee_leave_hrmanager.name
|
||||
employee_leave_hrmanager.action_approve()
|
||||
self.assertEqual(employee_leave_hrmanager.state, 'validate')
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import tests
|
||||
from odoo.addons.hr_holidays.tests.common import TestHrHolidaysBase
|
||||
|
||||
|
||||
class TestChangeDepartment(TestHrHolidaysBase):
|
||||
|
||||
def test_employee_change_department_request_change_department(self):
|
||||
self.HolidaysEmployeeGroup = self.env['hr.leave'].with_user(self.user_employee_id)
|
||||
|
||||
@@ -68,4 +66,3 @@ class TestChangeDepartment(TestHrHolidaysBase):
|
||||
hol32_user_group.action_refuse()
|
||||
self.employee_emp.department_id = self.hr_dept # Change department
|
||||
self.assertEqual(hol32_employee_group.department_id, self.hr_dept, 'hr_holidays: refused futur leave request should change department if employee change department')
|
||||
|
||||
|
||||
@@ -189,6 +189,7 @@ class TestHolidaysFlow(TestHrHolidaysBase):
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<odoo>
|
||||
|
||||
<menuitem
|
||||
name="Time Off"
|
||||
id="menu_hr_holidays_root"
|
||||
sequence="95"
|
||||
web_icon="hr_holidays,static/description/icon.png"
|
||||
groups="base.group_user"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_my_leaves"
|
||||
name="My Time Off"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_leave_menu_new_request"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_action_new_request"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_leave_menu_my"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_action_my"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_open_allocation"
|
||||
name="Allocation Requests"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_allocation_action_my"
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_dashboard"
|
||||
name="Everyone"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="2"
|
||||
action="action_hr_holidays_dashboard"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_approvals"
|
||||
name="Managers"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="3"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_user"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_approve"
|
||||
name="To Approve"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_user"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_open_department_leave_approve"
|
||||
name="Time Off"
|
||||
parent="hr_holidays_menu_manager_approve"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_action_action_approve_department"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_approve_allocations"
|
||||
name="Allocations"
|
||||
parent="hr_holidays_menu_manager_approve"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_allocation_action_approve_department"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_all"
|
||||
name="All"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_user"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_open_employee_leave"
|
||||
name="Time Off"
|
||||
parent="hr_holidays_menu_manager_all"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_action_all"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_all_allocations"
|
||||
name="Allocations"
|
||||
parent="hr_holidays_menu_manager_all"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_allocation_action_all"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_payroll"
|
||||
name="Payroll"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_payroll_to_report"
|
||||
name="Time Off to Report"
|
||||
parent="hr_holidays_menu_manager_payroll"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_action_payroll"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_report"
|
||||
name="Reporting"
|
||||
parent="menu_hr_holidays_root"
|
||||
groups="hr_holidays.group_hr_holidays_manager"
|
||||
sequence="4"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_available_holidays_report_tree"
|
||||
name="Time Off Analysis"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="action_hr_available_holidays_report"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_summary_dept"
|
||||
name="Report by Department"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="action_hr_holidays_summary_dept"
|
||||
sequence="2"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_configuration"
|
||||
name="Configuration"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="5"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_status_menu_configuration"
|
||||
action="open_view_holiday_status"
|
||||
name="Time Off Types"
|
||||
parent="menu_hr_holidays_configuration"
|
||||
groups="hr_holidays.group_hr_holidays_user"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem id="hr_holidays_menu_config_activity_type"
|
||||
action="mail_activity_type_action_config_hr_holidays"
|
||||
parent="menu_hr_holidays_configuration"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
</odoo>
|
||||
@@ -88,8 +88,7 @@
|
||||
<group>
|
||||
<field name="type_request_unit" invisible="1"/>
|
||||
<field name="name" attrs="{'readonly': [('state', 'not in', ('draft', 'confirm'))]}"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id}"
|
||||
domain="[('valid', '=', True), ('allocation_type', '=', 'fixed_allocation')]"/>
|
||||
<field name="holiday_status_id" context="{'employee_id':employee_id}"/>
|
||||
|
||||
<field name="number_of_days" invisible="1"/>
|
||||
<label for="number_of_days" string="Duration"/>
|
||||
@@ -136,9 +135,6 @@
|
||||
<button string="Reset to Draft" name="action_draft" type="object"
|
||||
attrs="{'invisible': ['|', ('can_reset', '=', False), ('state', 'not in', ['confirm', 'refuse'])]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='holiday_status_id']" position="attributes">
|
||||
<attribute name="domain">[('valid', '=', True)]</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='employee_id']" position="before">
|
||||
<field name="holiday_type" string="Mode" groups="hr_holidays.group_hr_holidays_user" context="{'employee_id':employee_id}" />
|
||||
</xpath>
|
||||
@@ -385,26 +381,4 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_open_allocation"
|
||||
name="Allocation Requests"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_allocation_action_my"
|
||||
sequence="6"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_approve_allocations"
|
||||
name="Allocations"
|
||||
parent="hr_holidays_menu_manager_approve"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_allocation_action_approve_department"
|
||||
sequence="2"/>
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_all_allocations"
|
||||
name="Allocations"
|
||||
parent="hr_holidays_menu_manager_all"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_allocation_action_all"
|
||||
sequence="2"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</xpath>
|
||||
<xpath expr="link[last()]" position="after">
|
||||
<link rel="stylesheet" type="text/scss" href="/hr_holidays/static/scss/hr_leave_mobile.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/hr_holidays/static/src/scss/time_off.scss"/>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="qunit_suite" name="hr_holidays_qunit_suite" inherit_id="web.qunit_suite">
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="code"/>
|
||||
<field name="request_unit" widget="radio"/>
|
||||
<field name="sequence" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group name="validation" string="Validation">
|
||||
<field name="validation_type" widget="radio"/>
|
||||
@@ -105,7 +104,6 @@
|
||||
<field name="model">hr.leave.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Time Off Type">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="display_name"/>
|
||||
<field name="code"/>
|
||||
<field name="allocation_type"/>
|
||||
@@ -124,18 +122,4 @@
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_configuration"
|
||||
name="Configuration"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="100"/>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_status_menu_configuration"
|
||||
action="open_view_holiday_status"
|
||||
name="Time Off Types"
|
||||
parent="menu_hr_holidays_configuration"
|
||||
groups="hr_holidays.group_hr_holidays_user"
|
||||
sequence="1"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,38 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.actions.server" id="action_report_to_payslip">
|
||||
<field name="name">Report to Payslip</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="binding_model_id" ref="model_hr_leave" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
records.write({'payslip_status': True})
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.server" id="action_manager_approval">
|
||||
<field name="name">Manager Approval</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="binding_model_id" ref="model_hr_leave" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
records.action_approve()
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.actions.server" id="action_hr_approval">
|
||||
<field name="name">HR Approval</field>
|
||||
<field name="model_id" ref="model_hr_leave"/>
|
||||
<field name="binding_model_id" ref="model_hr_leave" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
if records:
|
||||
records.action_validate()
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_evaluation_report_graph" model="ir.ui.view">
|
||||
<field name="name">hr.holidays.graph</field>
|
||||
<field name="model">hr.leave</field>
|
||||
@@ -32,10 +64,10 @@
|
||||
<separator/>
|
||||
<filter string="My Department Time Off" name="department" domain="['|', ('department_id.member_ids.user_id', '=', uid), ('employee_id.user_id', '=', uid)]" help="My Department Time Off"/>
|
||||
<filter string="People I Manage" name="managed_people" domain="[('employee_id.parent_id.user_id', '=', uid)]" help="Time off of people you are manager of"/>
|
||||
<filter string="My Team Time Off" name="my_team_leaves" domain="[('employee_id.leave_manager_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_team_leader" help="Time off of Your Team Members"/>
|
||||
<filter string="My Team Time Off" name="my_team_leaves" domain="[('employee_id.leave_manager_id', '=', uid)]" groups="hr_holidays.group_hr_holidays_user" help="Time off of Your Team Members"/>
|
||||
<filter string="My Time Off" name="my_leaves" domain="[('employee_id.user_id', '=', uid)]"/>
|
||||
<separator/>
|
||||
<filter string="To Report in Payslip" name="gray" domain="[('payslip_status', '=', False)]" groups="hr_holidays.group_hr_holidays_manager"/>
|
||||
<filter string="To Report in Payslip" name="gray" domain="[('payslip_status', '=', False)]" groups="hr_holidays.group_hr_holidays_user"/>
|
||||
<separator/>
|
||||
<filter string="To Do" name="todo" domain="[('payslip_status', '=', False), ('holiday_status_id.active', '=', True)]"/>
|
||||
<separator/>
|
||||
@@ -54,7 +86,6 @@
|
||||
<filter name="group_name" string="Description" context="{'group_by':'name'}"/>
|
||||
<filter name="group_employee" string="Employee" context="{'group_by':'employee_id'}"/>
|
||||
<filter name="group_category" string="Category" context="{'group_by':'category_id'}"/>
|
||||
<filter name="group_manager" string="Manager" context="{'group_by':'manager_id'}"/>
|
||||
<filter name="group_second_approver_id" string="Validator" context="{'group_by':'second_approver_id'}"/>
|
||||
<filter name="group_type" string="Type" context="{'group_by':'holiday_status_id'}"/>
|
||||
<separator/>
|
||||
@@ -190,6 +221,7 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<!-- RLI FIXME: we should avoid redefining the domain in the view when there already is a domain on the model -->
|
||||
<field name="holiday_status_id" domain="['|',('allocation_type', 'in', ['fixed_allocation', 'no']),'&',('allocation_type', '=', 'fixed'), ('max_leaves', '>', '0')]" context="{'employee_id':employee_id, 'default_date_from':date_from}" options="{'no_create': True, 'no_open': True}"/>
|
||||
|
||||
<label for="request_date_from" string="From"/>
|
||||
@@ -332,7 +364,7 @@
|
||||
'required': [('holiday_type', '=', 'department')],
|
||||
'invisible': [('holiday_type', 'not in', ('employee', 'department'))]
|
||||
}"/>
|
||||
<field name="payslip_status" groups="hr_holidays.group_hr_holidays_manager" widget="toggle_button"/>
|
||||
<field name="payslip_status" groups="hr_holidays.group_hr_holidays_user" widget="toggle_button"/>
|
||||
</group>
|
||||
<div groups="hr_holidays.group_hr_holidays_manager">
|
||||
<separator string="Comment by Manager"/>
|
||||
@@ -342,6 +374,16 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_view_calendar" model="ir.ui.view">
|
||||
<field name="name">hr.leave.view.calendar</field>
|
||||
<field name="model">hr.leave</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Time Off Request" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" color="employee_id">
|
||||
<field name="display_name"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_view_form_manager_approve" model="ir.ui.view">
|
||||
<field name="name">hr.leave.view.form.manager.approve</field>
|
||||
<field name="model">hr.leave</field>
|
||||
@@ -365,16 +407,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_view_calendar" model="ir.ui.view">
|
||||
<field name="name">hr.leave.view.calendar</field>
|
||||
<field name="model">hr.leave</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Time Off Request" event_open_popup="true" date_start="date_from" date_stop="date_to" mode="month" quick_add="False" color="employee_id">
|
||||
<field name="display_name"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_view_tree" model="ir.ui.view">
|
||||
<field name="name">hr.holidays.view.tree</field>
|
||||
<field name="model">hr.leave</field>
|
||||
@@ -390,10 +422,9 @@
|
||||
<field name="date_to"/>
|
||||
<field name="duration_display"/>
|
||||
<field name="state"/>
|
||||
<field name="payslip_status" widget="toggle_button" options='{"active": "Reported in last payslips", "inactive": "To Report in Payslip"}' groups="hr_holidays.group_hr_holidays_manager"/>
|
||||
<field name="payslip_status" widget="toggle_button" options='{"active": "Reported in last payslips", "inactive": "To Report in Payslip"}' groups="hr_holidays.group_hr_holidays_user"/>
|
||||
<field name="category_id" invisible="1"/>
|
||||
<field name="department_id" invisible="1"/>
|
||||
<field name="manager_id" invisible="1"/>
|
||||
<field name="user_id" invisible="1"/>
|
||||
<field name="message_needaction" invisible="1"/>
|
||||
<button string="Approve" name="action_approve" type="object"
|
||||
@@ -440,71 +471,16 @@
|
||||
<record id="action_hr_holidays_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">All Time Off</field>
|
||||
<field name="res_model">hr.leave</field>
|
||||
<field name="view_mode">calendar,tree</field>
|
||||
<field name="view_mode">calendar,tree,form</field>
|
||||
<field name="context">{
|
||||
'search_default_year': 1,
|
||||
'search_default_group_employee': 1,
|
||||
'search_default_managed_people': 1,
|
||||
'search_default_my_team_leaves': 1,
|
||||
'form_view_ref': 'hr_holidays.hr_leave_view_form_manager',
|
||||
}</field>
|
||||
<field name="domain">[('holiday_type','=','employee'), ('state', '!=', 'refuse')]</field>
|
||||
<field name="search_view_id" ref="view_hr_holidays_filter"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Time Off"
|
||||
id="menu_hr_holidays_root"
|
||||
sequence="95"
|
||||
web_icon="hr_holidays,static/description/icon.png"
|
||||
groups="base.group_user"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_dashboard"
|
||||
name="My Team"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="1"
|
||||
action="action_hr_holidays_dashboard"
|
||||
groups="hr_holidays.group_hr_holidays_manager"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_my_leaves"
|
||||
name="My Time Off"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_approvals"
|
||||
name="Managers"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="4"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_team_leader"/>
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_approve"
|
||||
name="To Approve"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_team_leader"
|
||||
sequence="1"/>
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_all"
|
||||
name="All"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_team_leader"
|
||||
sequence="2"/>
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_payroll"
|
||||
name="Payroll"
|
||||
parent="menu_hr_holidays_approvals"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
sequence="3"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_hr_holidays_report"
|
||||
name="Reporting"
|
||||
parent="menu_hr_holidays_root"
|
||||
sequence="99"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"/>
|
||||
|
||||
<record id="hr_leave_action_new_request" model="ir.actions.act_window">
|
||||
<field name="name">Dashboard</field>
|
||||
<field name="res_model">hr.leave</field>
|
||||
@@ -518,18 +494,21 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_action_new_request_view_calendar" model="ir.actions.act_window.view">
|
||||
<field name="sequence">1</field>
|
||||
<field name="view_mode">calendar</field>
|
||||
<field name="act_window_id" ref="hr_leave_action_new_request"/>
|
||||
<field name="view_id" ref="hr_leave_view_dashboard"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_action_new_request_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence">2</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="act_window_id" ref="hr_leave_action_new_request"/>
|
||||
<field name="view_id" ref="hr_leave_view_tree_my"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_action_new_request_view_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence">3</field>
|
||||
<field name="view_mode">form</field>
|
||||
@@ -537,12 +516,6 @@
|
||||
<field name="view_id" ref="hr_leave_view_form"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="hr_leave_menu_new_request"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_action_new_request"
|
||||
sequence="2"/>
|
||||
|
||||
<record id="hr_leave_action_my_request" model="ir.actions.act_window">
|
||||
<field name="name">Time Off Requests</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
@@ -571,12 +544,14 @@
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_action_my_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence">1</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="act_window_id" ref="hr_leave_action_my"/>
|
||||
<field name="view_id" ref="hr_leave_view_tree_my"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_leave_action_my_view_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence">2</field>
|
||||
<field name="view_mode">form</field>
|
||||
@@ -584,12 +559,6 @@
|
||||
<field name="view_id" ref="hr_leave_view_form"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="hr_leave_menu_my"
|
||||
parent="menu_hr_holidays_my_leaves"
|
||||
action="hr_leave_action_my"
|
||||
sequence="4"/>
|
||||
|
||||
<record id="hr_leave_action_all" model="ir.actions.act_window">
|
||||
<field name="name">Time Off</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
@@ -651,21 +620,6 @@
|
||||
<field name="domain">[('holiday_type','=','employee')]</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_open_department_leave_approve"
|
||||
name="Time Off"
|
||||
parent="hr_holidays_menu_manager_approve"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_team_leader"
|
||||
action="hr_leave_action_action_approve_department"
|
||||
sequence="1"/>
|
||||
<menuitem
|
||||
id="menu_open_employee_leave"
|
||||
name="Time Off"
|
||||
parent="hr_holidays_menu_manager_all"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user,hr_holidays.group_hr_holidays_team_leader"
|
||||
action="hr_leave_action_all"
|
||||
sequence="1"/>
|
||||
|
||||
<record id="hr_leave_action_payroll" model="ir.actions.act_window">
|
||||
<field name="name">Time Off Requests</field>
|
||||
<field name="res_model">hr.leave</field>
|
||||
@@ -681,14 +635,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="hr_holidays_menu_manager_payroll_to_report"
|
||||
name="Time Off to report"
|
||||
parent="hr_holidays_menu_manager_payroll"
|
||||
groups="hr_holidays.group_hr_holidays_manager,hr_holidays.group_hr_holidays_user"
|
||||
action="hr_leave_action_payroll"
|
||||
sequence="1"/>
|
||||
|
||||
<record id="view_holiday_pivot" model="ir.ui.view">
|
||||
<field name="name">hr.holidays.report_pivot</field>
|
||||
<field name="model">hr.leave</field>
|
||||
@@ -728,9 +674,4 @@
|
||||
<field name="act_window_id" ref="action_hr_available_holidays_report"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Time Off Analysis"
|
||||
id="menu_hr_available_holidays_report_tree"
|
||||
action="action_hr_available_holidays_report"
|
||||
parent="menu_hr_holidays_report" sequence="5"/>
|
||||
</odoo>
|
||||
|
||||
@@ -8,8 +8,4 @@
|
||||
<field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['hr.leave', 'hr.leave.allocation'])]</field>
|
||||
<field name="context">{'default_res_model': 'hr.leave'}</field>
|
||||
</record>
|
||||
<menuitem id="hr_holidays_menu_config_activity_type"
|
||||
action="mail_activity_type_action_config_hr_holidays"
|
||||
parent="menu_hr_holidays_configuration"
|
||||
groups="base.group_no_one"/>
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
||||
@@ -27,10 +27,4 @@
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Report by Department"
|
||||
parent="menu_hr_holidays_report"
|
||||
action="action_hr_holidays_summary_dept"
|
||||
id="menu_hr_holidays_summary_dept"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user