Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,8 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_browsable_object
from . import test_hr_payslip_worked_days
from . import test_hr_salary_rule
from . import test_payslip_flow
from . import test_hr_payroll_cancel
from . import test_hr_payslip_change_state

View file

@ -0,0 +1,219 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo.fields import Date
from odoo.tests.common import TransactionCase
class TestPayslipBase(TransactionCase):
def setUp(self):
super(TestPayslipBase, self).setUp()
self.Payslip = self.env["hr.payslip"]
self.RuleInput = self.env["hr.rule.input"]
self.SalaryRule = self.env["hr.salary.rule"]
self.SalaryRuleCateg = self.env["hr.salary.rule.category"]
self.Contract = self.env["hr.contract"]
self.ResourceCalendar = self.env["resource.calendar"]
self.CalendarAttendance = self.env["resource.calendar.attendance"]
# Salary Rule Categories
#
self.categ_basic = self.SalaryRuleCateg.create(
{
"name": "Basic",
"code": "BASIC",
}
)
self.categ_alw = self.SalaryRuleCateg.create(
{
"name": "Allowance",
"code": "ALW",
}
)
self.categ_gross = self.SalaryRuleCateg.create(
{
"name": "Gross",
"code": "GROSS",
}
)
self.categ_ded = self.SalaryRuleCateg.create(
{
"name": "Deduction",
"code": "DED",
}
)
self.categ_net = self.SalaryRuleCateg.create(
{
"name": "NET",
"code": "NET",
}
)
#
# Salary Rules
#
# Earnings
#
self.rule_basic = self.SalaryRule.create(
{
"name": "Basic Salary",
"code": "BASIC",
"sequence": 1,
"category_id": self.categ_basic.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": "result = contract.wage",
}
)
self.rule_hra = self.SalaryRule.create(
{
"name": "House Rent Allowance",
"code": "HRA",
"sequence": 5,
"category_id": self.categ_alw.id,
"condition_select": "none",
"amount_select": "percentage",
"amount_percentage": 40.0,
"amount_percentage_base": "contract.wage",
}
)
self.rule_meal = self.SalaryRule.create(
{
"name": "Meal Voucher",
"code": "MA",
"sequence": 16,
"category_id": self.categ_alw.id,
"condition_select": "none",
"amount_select": "fix",
"amount_fix": 10.0,
"quantity": "worked_days.WORK100 and worked_days.WORK100.number_of_days",
}
)
self.rule_commission = self.SalaryRule.create(
{
"name": "Get 1% of sales",
"code": "SALE",
"sequence": 17,
"category_id": self.categ_alw.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": "result = "
"(inputs.SALEURO and inputs.SALEURO.amount) * 0.01",
}
)
self.RuleInput.create(
{
"name": "Sales to Europe",
"code": "SALEURO",
"input_id": self.rule_commission.id,
}
)
# Gross
#
self.rule_gross = self.SalaryRule.create(
{
"name": "Gross",
"code": "GROSS",
"sequence": 100,
"category_id": self.categ_gross.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": "result = categories.BASIC + categories.ALW",
}
)
# Deductions
#
self.rule_proftax = self.SalaryRule.create(
{
"name": "Professional Tax",
"code": "PT",
"sequence": 150,
"category_id": self.categ_ded.id,
"condition_select": "none",
"amount_select": "fix",
"amount_fix": -200.0,
}
)
# Net
#
self.rule_net = self.SalaryRule.create(
{
"name": "Net",
"code": "NET",
"sequence": 200,
"category_id": self.categ_net.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": "result = categories.BASIC "
"+ categories.ALW + categories.DED",
}
)
# Test Child Line
#
self.rule_child = self.SalaryRule.create(
{
"name": "Net Child Rule",
"code": "NET_CHILD",
"sequence": 190,
"category_id": self.categ_net.id,
"parent_rule_id": self.rule_net.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": "result = categories.BASIC "
"+ categories.ALW + categories.DED",
}
)
# I create a new employee "Richard"
self.richard_emp = self.env["hr.employee"].create(
{
"name": "Richard",
"gender": "male",
"birthday": "1984-05-01",
"country_id": self.ref("base.be"),
"department_id": self.ref("hr.dep_rd"),
}
)
# I create a salary structure for "Software Developer"
self.developer_pay_structure = self.env["hr.payroll.structure"].create(
{
"name": "Salary Structure for Software Developer",
"code": "SD",
"company_id": self.ref("base.main_company"),
"rule_ids": [
(4, self.rule_hra.id),
(4, self.rule_proftax.id),
(4, self.rule_meal.id),
(4, self.rule_commission.id),
(4, self.rule_basic.id),
(4, self.rule_gross.id),
(4, self.rule_net.id),
],
}
)
# I create a contract for "Richard"
self.env["hr.contract"].create(
{
"date_end": Date.to_string(datetime.now() + timedelta(days=365)),
"date_start": Date.today(),
"name": "Contract for Richard",
"wage": 5000.0,
"employee_id": self.richard_emp.id,
"struct_id": self.developer_pay_structure.id,
"kanban_state": "done",
}
)
def apply_contract_cron(self):
self.env.ref(
"hr_contract.ir_cron_data_contract_update_state"
).method_direct_trigger()

View file

@ -0,0 +1,72 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.payroll.models.hr_payslip import BaseBrowsableObject, BrowsableObject
from .common import TestPayslipBase
class TestBrowsableObject(TestPayslipBase):
def setUp(self):
super().setUp()
def test_init(self):
obj = BrowsableObject(self.richard_emp.id, {"test": 1}, self.env)
self.assertEqual(obj.test, 1, "Simple initialization")
self.assertEqual(
obj.employee_id,
self.richard_emp.id,
"Employee Id is retrieved successfully",
)
self.assertEqual(obj.env, self.env, "Env is retrieved successfully")
d = {
"level1": BaseBrowsableObject(
{
"level2": 10,
"env": 900.0,
},
)
}
obj = BrowsableObject(self.richard_emp.id, d, self.env)
self.assertEqual(obj.level1.level2, 10, "Nested initialization")
self.assertEqual(
obj.employee_id,
self.richard_emp.id,
"Employee Id is retrieved successfully from nested dictionary",
)
self.assertEqual(
obj.env, self.env, "Env is retrieved successfully from nested dictionary"
)
self.assertEqual(
obj.level1.employee_id, 0.0, "Employee Id is *NOT* in BaseBrowsableObject"
)
self.assertEqual(
obj.level1.env,
900.0,
"Env is *IN* BaseBrowsableObject, but it's in user-defined dictionary",
)
def test_update_attribute(self):
obj = BrowsableObject(
self.richard_emp.id,
{
"foo": BaseBrowsableObject(
{
"bar": 200.0,
}
)
},
self.env,
)
self.assertEqual(obj.foo.bar, 200.0, "Nested initialization succeeded")
obj.foo.bar = 350.0
self.assertEqual(
obj.foo.bar,
350.0,
"Updating of attribute using dot ('.') notation succeeded",
)

View file

@ -0,0 +1,89 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from dateutil import relativedelta
from odoo.exceptions import ValidationError
from odoo.tests import common
class TestHrPayrollCancel(common.TransactionCase):
def setUp(self):
super(TestHrPayrollCancel, self).setUp()
# Set system parameter
self.env["ir.config_parameter"].sudo().set_param(
"payroll.allow_cancel_payslips", True
)
self.payslip_action_id = self.ref("payroll.hr_payslip_menu")
self.res_partner_bank = self.env["res.partner.bank"].create(
{
"acc_number": "001-9876543-21",
"partner_id": self.ref("base.res_partner_12"),
"acc_type": "bank",
"bank_id": self.ref("base.res_bank_1"),
}
)
self.hr_employee_anita = self.env.ref("hr.employee_mit")
self.hr_structure_marketing_executive = self.ref("payroll.structure_001")
self.hr_contract_anita = self.env.ref("hr_contract.hr_contract_mit")
self.hr_payslip = self.env["hr.payslip"].create(
{
"employee_id": self.hr_employee_anita.id,
}
)
def test_refund_sheet(self):
hr_payslip = self._create_payslip()
hr_payslip.action_payslip_done()
hr_payslip.refund_sheet()
with self.assertRaises(ValidationError):
hr_payslip.action_payslip_cancel()
self.assertEqual(hr_payslip.refunded_id.state, "done")
hr_payslip.refunded_id.action_payslip_cancel()
self.assertEqual(hr_payslip.refunded_id.state, "cancel")
self.assertEqual(hr_payslip.state, "done")
hr_payslip.action_payslip_cancel()
self.assertEqual(hr_payslip.state, "cancel")
def _create_payslip(self):
date_from = datetime.now()
date_to = datetime.now() + relativedelta.relativedelta(
months=+2, day=1, days=-1
)
res = self.hr_payslip.get_payslip_vals(
date_from, date_to, self.hr_employee_anita.id
)
vals = {
"struct_id": res["value"]["struct_id"],
"contract_id": res["value"]["contract_id"],
"name": res["value"]["name"],
}
vals["worked_days_line_ids"] = [
(0, 0, i) for i in res["value"]["worked_days_line_ids"]
]
vals["input_line_ids"] = [(0, 0, i) for i in res["value"]["input_line_ids"]]
vals.update({"contract_id": self.hr_contract_anita.id})
self.hr_payslip.write(vals)
payslip_input = self.env["hr.payslip.input"].search(
[("payslip_id", "=", self.hr_payslip.id)]
)
payslip_input.write({"amount": 5.0})
context = {
"lang": "en_US",
"tz": False,
"active_model": "hr.payslip",
"department_id": False,
"active_ids": [self.payslip_action_id],
"section_id": False,
"active_id": self.payslip_action_id,
}
self.hr_payslip.with_context(context).compute_sheet()
return self.hr_payslip
def test_action_payslip_cancel(self):
hr_payslip = self._create_payslip()
hr_payslip.action_payslip_done()
hr_payslip.refund_sheet()
hr_payslip.refunded_id.action_payslip_cancel()
hr_payslip.action_payslip_cancel()

View file

@ -0,0 +1,60 @@
# Copyright 2019 - Eficent http://www.eficent.com/
# Copyright 2019 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.exceptions import UserError
from odoo.addons.payroll.tests.test_hr_payroll_cancel import TestHrPayrollCancel
class TestHrPayslipChangeState(TestHrPayrollCancel):
def setUp(self):
super(TestHrPayslipChangeState, self).setUp()
self.tested_model = self.env["hr.payslip.change.state"]
def test_change_state(self):
hr_payslip = self._create_payslip()
tested_model = self.tested_model
context = {"active_ids": [hr_payslip.id]}
action = tested_model.with_context(context).create({"state": "verify"})
# By default, a payslip is on draft state
action.change_state_confirm()
# trying to set it to wrong states
with self.assertRaises(UserError):
action.write({"state": "draft"})
action.change_state_confirm()
# Now the payslip should be computed but in verify state
self.assertEqual(hr_payslip.state, "verify")
self.assertNotEqual(hr_payslip.number, None)
action.write({"state": "done"})
action.change_state_confirm()
# Now the payslip should be confirmed
self.assertEqual(hr_payslip.state, "done")
# trying to set it to wrong states
with self.assertRaises(UserError):
action.write({"state": "draft"})
action.change_state_confirm()
with self.assertRaises(UserError):
action.write({"state": "verify"})
action.change_state_confirm()
with self.assertRaises(UserError):
action.write({"state": "done"})
action.change_state_confirm()
action.write({"state": "cancel"})
action.change_state_confirm()
# Now the payslip should be canceled
self.assertEqual(hr_payslip.state, "cancel")
# trying to set it to wrong states
with self.assertRaises(UserError):
action.write({"state": "done"})
action.change_state_confirm()
with self.assertRaises(UserError):
action.write({"state": "verify"})
action.change_state_confirm()
with self.assertRaises(UserError):
action.write({"state": "cancel"})
action.change_state_confirm()
action.write({"state": "draft"})
action.change_state_confirm()
# again, it should be draft. Also checking if wrong changes happened
self.assertEqual(hr_payslip.state, "draft")

View file

@ -0,0 +1,138 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import date, datetime
from odoo.tests.common import Form
from .common import TestPayslipBase
class TestWorkedDays(TestPayslipBase):
def setUp(self):
super().setUp()
self.LeaveRequest = self.env["hr.leave"]
self.LeaveType = self.env["hr.leave.type"]
# create holiday type
self.holiday_type = self.LeaveType.create(
{
"name": "TestLeaveType",
"code": "TESTLV",
"allocation_type": "no",
"leave_validation_type": "no_validation",
}
)
self.full_calendar = self.ResourceCalendar.create(
{
"name": "56 Hrs a week",
"tz": "UTC",
}
)
# Create a full 7-day week sor our tests don't fail on Sat. and Sun.
for day in ["0", "1", "2", "3", "4", "5", "6"]:
self.CalendarAttendance.create(
{
"calendar_id": self.full_calendar.id,
"dayofweek": day,
"name": "Morning",
"day_period": "morning",
"hour_from": 8,
"hour_to": 12,
}
)
self.CalendarAttendance.create(
{
"calendar_id": self.full_calendar.id,
"dayofweek": day,
"name": "Afternoon",
"day_period": "afternoon",
"hour_from": 13,
"hour_to": 17,
}
)
def _common_contract_leave_setup(self):
self.richard_emp.resource_id.calendar_id = self.full_calendar
self.richard_emp.contract_ids.resource_calendar_id = self.full_calendar
# I put all eligible contracts (including Richard's) in an "open" state
self.apply_contract_cron()
# Create the leave
self.LeaveRequest.create(
{
"name": "Hol11",
"employee_id": self.richard_emp.id,
"holiday_status_id": self.holiday_type.id,
"date_from": datetime.combine(date.today(), datetime.min.time()),
"date_to": datetime.combine(date.today(), datetime.max.time()),
"number_of_days": 1,
}
)
def test_worked_days_negative(self):
self._common_contract_leave_setup()
# Set system parameter
self.env["ir.config_parameter"].sudo().set_param(
"payroll.leaves_positive", False
)
# I create an employee Payslip
frm = Form(self.Payslip)
frm.employee_id = self.richard_emp
richard_payslip = frm.save()
worked_days_codes = richard_payslip.worked_days_line_ids.mapped("code")
self.assertIn(
"TESTLV", worked_days_codes, "The leave is in the 'Worked Days' list"
)
wdl_ids = richard_payslip.worked_days_line_ids.filtered(
lambda x: x.code == "TESTLV"
)
self.assertEqual(len(wdl_ids), 1, "There is only one line matching the leave")
self.assertEqual(
wdl_ids[0].number_of_days,
-1.0,
"The days worked value is a NEGATIVE number",
)
self.assertEqual(
wdl_ids[0].number_of_hours,
-8.0,
"The hours worked value is a NEGATIVE number",
)
def test_leaves_positive(self):
self._common_contract_leave_setup()
# Set system parameter
self.env["ir.config_parameter"].sudo().set_param(
"payroll.leaves_positive", True
)
# I create an employee Payslip
frm = Form(self.Payslip)
frm.employee_id = self.richard_emp
richard_payslip = frm.save()
worked_days_codes = richard_payslip.worked_days_line_ids.mapped("code")
self.assertIn(
"TESTLV", worked_days_codes, "The leave is in the 'Worked Days' list"
)
wdl_ids = richard_payslip.worked_days_line_ids.filtered(
lambda x: x.code == "TESTLV"
)
self.assertEqual(len(wdl_ids), 1, "There is only one line matching the leave")
self.assertEqual(
wdl_ids[0].number_of_days, 1.0, "The days worked value is a POSITIVE number"
)
self.assertEqual(
wdl_ids[0].number_of_hours,
8.0,
"The hours worked value is a POSITIVE number",
)

View file

@ -0,0 +1,69 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from .common import TestPayslipBase
class TestSalaryRule(TestPayslipBase):
def setUp(self):
super().setUp()
self.Payslip = self.env["hr.payslip"]
self.Rule = self.env["hr.salary.rule"]
self.test_rule = self.Rule.create(
{
"name": "test rule",
"code": "TEST",
"category_id": self.env.ref("payroll.ALW").id,
"sequence": 6,
"amount_select": "code",
"amount_python_compute": "result = 0",
}
)
self.developer_pay_structure.write({"rule_ids": [(4, self.test_rule.id)]})
def test_python_code_return_values(self):
self.test_rule.amount_python_compute = (
"result_rate = 0\n" "result_qty = 0\n" "result = 0\n"
)
# Open contracts
cc = self.env["hr.contract"].search([("employee_id", "=", self.richard_emp.id)])
cc.kanban_state = "done"
self.env.ref(
"hr_contract.ir_cron_data_contract_update_state"
).method_direct_trigger()
# Create payslip and compute
payslip = self.Payslip.create({"employee_id": self.richard_emp.id})
payslip.onchange_employee()
payslip.compute_sheet()
line = payslip.line_ids.filtered(lambda l: l.code == "TEST")
self.assertEqual(len(line), 1, "I found the Test line")
self.assertEqual(line.amount, 0.0, "The amount is zero")
self.assertEqual(line.rate, 0.0, "The rate is zero")
self.assertEqual(line.quantity, 0.0, "The quantity is zero")
def test_python_code_result_not_set(self):
self.test_rule.amount_python_compute = "result = 2"
# Open contracts
cc = self.env["hr.contract"].search([("employee_id", "=", self.richard_emp.id)])
cc.kanban_state = "done"
self.env.ref(
"hr_contract.ir_cron_data_contract_update_state"
).method_direct_trigger()
# Create payslip and compute
payslip = self.Payslip.create({"employee_id": self.richard_emp.id})
payslip.onchange_employee()
payslip.compute_sheet()
line = payslip.line_ids.filtered(lambda l: l.code == "TEST")
self.assertEqual(len(line), 1, "I found the Test line")
self.assertEqual(line.amount, 2.0, "The amount is zero")
self.assertEqual(line.rate, 100.0, "The rate is zero")
self.assertEqual(line.quantity, 1.0, "The quantity is zero")

View file

@ -0,0 +1,224 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.fields import Date
from odoo.tests import Form
from odoo.tools import test_reports
from .common import TestPayslipBase
class TestPayslipFlow(TestPayslipBase):
def setUp(self):
super().setUp()
self.test_rule = self.SalaryRule.create(
{
"name": "Test rule",
"code": "TEST",
"category_id": self.categ_alw.id,
"sequence": 5,
"amount_select": "code",
"amount_python_compute": "result = contract.wage",
}
)
def test_00_payslip_flow(self):
"""Testing payslip flow and report printing"""
# I put all eligible contracts (including Richard's) in an "open" state
self.apply_contract_cron()
# I create an employee Payslip
frm = Form(self.Payslip)
frm.employee_id = self.richard_emp
richard_payslip = frm.save()
payslip_input = self.env["hr.payslip.input"].search(
[("payslip_id", "=", richard_payslip.id), ("code", "=", "SALEURO")]
)
# I assign the amount to Input data
payslip_input.write({"amount": 5.0})
# I verify the payslip is in draft state
self.assertEqual(richard_payslip.state, "draft", "State not changed!")
context = {
"lang": "en_US",
"tz": False,
"active_model": "ir.ui.menu",
"department_id": False,
"section_id": False,
"active_ids": [self.ref("payroll.hr_payslip_menu")],
"active_id": self.ref("payroll.hr_payslip_menu"),
}
# I click on 'Compute Sheet' button on payslip
richard_payslip.with_context(context).compute_sheet()
# Check child rules shown in table by default
child_line = richard_payslip.dynamic_filtered_payslip_lines.filtered(
lambda l: l.code == "NET_CHILD"
)
self.assertEqual(
len(child_line), 1, "Child line found when flag desactivated (default)"
)
# Check parent line id value is correct
parent_line = richard_payslip.dynamic_filtered_payslip_lines.filtered(
lambda l: l.code == "NET"
)
self.assertEqual(
child_line.parent_line_id.code,
parent_line.code,
"Child line parent_id is correct",
)
# Check parent line id is False in a rule that have not parent defined
self.assertEqual(
len(parent_line.parent_line_id), 0, "The parent line has no parent_line_id"
)
# We change child rules show/hide flag
richard_payslip.hide_child_lines = True
# Check child rules not shown in table after flag changed
child_line = richard_payslip.dynamic_filtered_payslip_lines.filtered(
lambda l: l.code == "NET_CHILD"
)
self.assertEqual(
len(child_line), 0, "The child line is not found when flag activated"
)
# Find the 'NET' payslip line and check that it adds up
# salary + HRA + MA + SALE - PT
work100 = richard_payslip.worked_days_line_ids.filtered(
lambda x: x.code == "WORK100"
)
line = richard_payslip.line_ids.filtered(lambda l: l.code == "NET")
self.assertEqual(len(line), 1, "I found the 'NET' line")
self.assertEqual(
line[0].amount,
5000.0 + (0.4 * 5000) + (work100.number_of_days * 10) + 0.05 - 200.0,
"The 'NET' amount equals salary plus allowances - deductions",
)
# Then I click on the 'Confirm' button on payslip
richard_payslip.action_payslip_done()
# I verify that the payslip is in done state
self.assertEqual(richard_payslip.state, "done", "State not changed!")
# I want to check refund payslip so I click on refund button.
richard_payslip.refund_sheet()
# I check on new payslip Credit Note is checked or not.
payslip_refund = self.env["hr.payslip"].search(
[
("name", "like", "Refund: " + richard_payslip.name),
("credit_note", "=", True),
]
)
self.assertTrue(bool(payslip_refund), "Payslip not refunded!")
# I want to generate a payslip from Payslip run.
payslip_run = self.env["hr.payslip.run"].create(
{
"date_end": "2011-09-30",
"date_start": "2011-09-01",
"name": "Payslip for Employee",
}
)
# I create record for generating the payslip for this Payslip run.
payslip_employee = self.env["hr.payslip.employees"].create(
{"employee_ids": [(4, self.richard_emp.id)]}
)
# I generate the payslip by clicking on Generat button wizard.
payslip_employee.with_context(active_id=payslip_run.id).compute_sheet()
# I open Contribution Register and from there I print the Payslip Lines report.
self.env["payslip.lines.contribution.register"].create(
{"date_from": "2011-09-30", "date_to": "2011-09-01"}
)
# I print the payslip report
data, data_format = self.env.ref(
"payroll.action_report_payslip"
)._render_qweb_pdf(richard_payslip.ids)
# I print the payslip details report
data, data_format = self.env.ref(
"payroll.payslip_details_report"
)._render_qweb_pdf(richard_payslip.ids)
# I print the contribution register report
context = {
"model": "hr.contribution.register",
"active_ids": [self.ref("payroll.hr_houserent_register")],
}
test_reports.try_report_action(
self.env.cr,
self.env.uid,
"action_payslip_lines_contribution_register",
context=context,
our_module="payroll",
)
def test_contract_qty(self):
# I set the test rule to detect contract count
self.test_rule.amount_python_compute = (
"result = payroll.contracts and payroll.contracts.count or -1.0"
)
self.developer_pay_structure.write({"rule_ids": [(4, self.test_rule.id)]})
# I put all eligible contracts (including Richard's) in an "open" state
self.apply_contract_cron()
# I create an employee Payslip and process it
richard_payslip = self.Payslip.create({"employee_id": self.richard_emp.id})
richard_payslip.onchange_employee()
richard_payslip.compute_sheet()
line = richard_payslip.line_ids.filtered(lambda l: l.code == "TEST")
self.assertEqual(len(line), 1, "I found the Test line")
self.assertEqual(
line[0].amount, 1.0, "The calculated dictionary value 'contracts.qty' is 1"
)
def test_compute_multiple_payslips(self):
self.sally = self.env["hr.employee"].create(
{
"name": "Sally",
"department_id": self.ref("hr.dep_rd"),
}
)
self.env["hr.contract"].create(
{
"date_start": Date.today(),
"name": "Contract for Sally",
"wage": 5000.0,
"employee_id": self.sally.id,
"struct_id": self.developer_pay_structure.id,
"kanban_state": "done",
}
)
self.apply_contract_cron()
payslips = self.Payslip.create(
[
{"employee_id": self.richard_emp.id},
{"employee_id": self.sally.id},
]
)
payslips[0].onchange_employee()
payslips[1].onchange_employee()
self.assertEqual(len(payslips.ids), 2, "We have multiple payslips")
payslips.compute_sheet()
self.assertTrue(
payslips[0].number, "The first payslip as been assigned a number"
)
self.assertTrue(
payslips[1].number, "The second payslip as been assigned a number"
)