diff --git a/payroll/tests/test_payslip_flow.py b/payroll/tests/test_payslip_flow.py index 2640dfb64..d2a10aa11 100644 --- a/payroll/tests/test_payslip_flow.py +++ b/payroll/tests/test_payslip_flow.py @@ -2,6 +2,7 @@ from datetime import timedelta +from odoo.exceptions import UserError from odoo.fields import Date from odoo.tests import Form from odoo.tools import test_reports @@ -284,6 +285,93 @@ def test_compute_sheet_no_valid_contract(self): "There are no lines because there are no valid contracts", ) + def test_payslip_employees_clear_action(self): + payslip_run = self.env["hr.payslip.run"].create( + { + "date_end": "2011-09-30", + "date_start": "2011-09-01", + "name": "Payslip wizard clear employees", + } + ) + payslip_employee = self.env["hr.payslip.employees"].create( + {"employee_ids": [(4, self.richard_emp.id)]} + ) + + self.assertTrue( + payslip_employee.employee_ids, + "Wizard must start with at least one employee selected", + ) + + action = payslip_employee.with_context( + active_id=payslip_run.id, + active_model="hr.payslip.run", + ).action_clear_employees() + self.assertFalse( + payslip_employee.employee_ids, + "Wizard employee selection should be empty after clear action", + ) + self.assertTrue( + payslip_run.exists(), + "Payslip run must still exist after clear action on wizard", + ) + self.assertEqual( + action.get("res_id"), + payslip_employee.id, + "Clear action should keep current wizard record opened", + ) + self.assertEqual( + action.get("context", {}).get("active_id"), + payslip_run.id, + "Clear action should preserve active_id context for payslip run", + ) + + with self.assertRaises(UserError): + payslip_employee.with_context(active_id=payslip_run.id).compute_sheet() + + def test_payslip_employees_apply_filter_action(self): + department = self.env["hr.department"].create( + {"name": "Payroll Filter Department"} + ) + job = self.env["hr.job"].create({"name": "Payroll Filter Job"}) + employee_match = self.env["hr.employee"].create( + { + "name": "Payroll Employee Match", + "department_id": department.id, + "job_id": job.id, + "company_id": self.env.company.id, + } + ) + employee_other = self.env["hr.employee"].create( + { + "name": "Payroll Employee Other", + "company_id": self.env.company.id, + } + ) + payslip_employee = self.env["hr.payslip.employees"].create( + { + "company_id": self.env.company.id, + "department_id": department.id, + "job_id": job.id, + "employee_ids": [(4, employee_other.id)], + } + ) + + action = payslip_employee.with_context( + active_id=999, + active_model="hr.payslip.run", + ).action_apply_employee_filter() + + self.assertEqual( + payslip_employee.employee_ids.ids, + employee_match.ids, + "Apply Filter must replace selected employees with domain results", + ) + self.assertEqual( + action.get("context", {}).get("active_id"), + 999, + "Apply Filter should preserve active_id context", + ) + def _get_developer_rules(self): developer_rules = self.SalaryRule developer_rules |= self.rule_basic diff --git a/payroll/wizard/hr_payroll_payslips_by_employees.py b/payroll/wizard/hr_payroll_payslips_by_employees.py index d1d7c84cd..d2474bfef 100644 --- a/payroll/wizard/hr_payroll_payslips_by_employees.py +++ b/payroll/wizard/hr_payroll_payslips_by_employees.py @@ -6,10 +6,48 @@ class HrPayslipEmployees(models.TransientModel): _name = "hr.payslip.employees" _description = "Generate payslips for all selected employees" + company_id = fields.Many2one( + "res.company", + string="Company", + default=lambda self: self.env.company, + ) + department_id = fields.Many2one("hr.department", string="Department") + job_id = fields.Many2one("hr.job", string="Job Position") employee_ids = fields.Many2many( "hr.employee", "hr_employee_group_rel", "payslip_id", "employee_id", "Employees" ) + def _get_reopen_wizard_action(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "res_model": self._name, + "res_id": self.id, + "view_mode": "form", + "target": "new", + "context": dict(self.env.context), + } + + def action_apply_employee_filter(self): + self.ensure_one() + domain = [] + if self.company_id: + domain.append(("company_id", "=", self.company_id.id)) + if self.department_id: + domain.append(("department_id", "=", self.department_id.id)) + if self.job_id: + domain.append(("job_id", "=", self.job_id.id)) + employee_ids = self.env["hr.employee"].search(domain).ids + self.write({"employee_ids": [(6, 0, employee_ids)]}) + return self._get_reopen_wizard_action() + + def action_clear_employees(self): + self.ensure_one() + self.write({"employee_ids": [(5, 0, 0)]}) + # Preserve originating action context (active_id on hr.payslip.run). A dict + # return is required: other truthy values become act_window_close in web. + return self._get_reopen_wizard_action() + def compute_sheet(self): payslips = self.env["hr.payslip"] [data] = self.read() diff --git a/payroll/wizard/hr_payroll_payslips_by_employees_views.xml b/payroll/wizard/hr_payroll_payslips_by_employees_views.xml index c738634f9..d86de8671 100644 --- a/payroll/wizard/hr_payroll_payslips_by_employees_views.xml +++ b/payroll/wizard/hr_payroll_payslips_by_employees_views.xml @@ -6,6 +6,20 @@
+