[IMP] cli: add scaffold for payroll localization

Added few basic rules and folders that are usually common to most localizations.
The template will also serve as documentation on naming conventions (not strict atm).

closes odoo/odoo#121446

Usage: ./odoo_bin scaffold -t l10n_payroll name-code (e.g. estonia-ee) [destination]
Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
dasz
2023-06-26 16:41:35 +02:00
parent c3ffbd338b
commit d7df1856fa
15 changed files with 533 additions and 1 deletions
+15 -1
View File
@@ -32,10 +32,20 @@ class Scaffold(Command):
sys.exit(parser.print_help())
args = parser.parse_args(args=cmdargs)
if args.template.id == 'l10n_payroll':
name_split = args.name.split('-')
params = {
'name': name_split[0],
'code': name_split[1]
}
else:
params = {'name': args.name}
args.template.render_to(
snake(args.name),
directory(args.dest, create=True),
{'name': args.name})
params=params,
)
def epilog(self):
return "Built-in templates available are: %s" % ', '.join(
@@ -109,11 +119,14 @@ class template(object):
"""
# overwrite with local
for path, content in self.files():
path = env.from_string(path).render(params)
local = os.path.relpath(path, self.path)
# strip .template extension
root, ext = os.path.splitext(local)
if ext == '.template':
local = root
if self.id == "l10n_payroll":
modname = f"l10n_{params['code']}_hr_payroll"
dest = os.path.join(directory, modname, local)
destdir = os.path.dirname(dest)
if not os.path.exists(destdir):
@@ -126,6 +139,7 @@ class template(object):
env.from_string(content.decode('utf-8'))\
.stream(params or {})\
.dump(f, encoding='utf-8')
f.write(b'\n')
def die(message, code=1):
print(message, file=sys.stderr)
@@ -0,0 +1,3 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
@@ -0,0 +1,36 @@
{%- set countryPascal = name|pascal -%}
{%- set codeUpper = code|upper -%}
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '{{countryPascal}} - Payroll',
'countries': ['{{code}}'],
'category': 'Human Resources/Payroll',
'depends': ['hr_payroll'],
'version': '1.0',
'description': """
''Country-ish'' Payroll Rules.
==============================
* Employee Details
* Employee Contracts
* Passport based Contract
* Allowances/Deductions
* Allow to configure Basic/Gross/Net Salary
* Employee Payslip
* Integrated with Leaves Management
""",
'data': [
'data/hr_salary_rule_category_data.xml',
'data/hr_payroll_structure_type_data.xml',
'views/hr_payroll_report.xml',
'data/hr_payroll_structure_data.xml',
'data/hr_rule_parameters_data.xml',
'data/hr_salary_rule_data.xml',
'views/report_payslip_templates.xml',
],
'demo': [
'data/l10n_{{code}}_hr_payroll_demo.xml',
],
'license': 'OEEL-1',
}
@@ -0,0 +1,14 @@
{%- set countryPascal = name|pascal -%}
{%- set codeUpper = code|upper -%}
<odoo>
<record id="l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary" model="hr.payroll.structure">
<field name="name">{{countryPascal}}: Regular Pay</field>
<field name="code">{{codeUpper}}MONTHLY</field>
<field name="country_id" ref="base.{{code}}"/>
<field name="type_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_structure_type_employee_{{code}}"/>
<field name="report_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_action_report_payslip_{{code}}"/>
</record>
<record id="l10n_{{code}}_hr_payroll.l10n_{{code}}_structure_type_employee_{{code}}" model="hr.payroll.structure.type">
<field name="default_struct_id" ref="l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
</odoo>
@@ -0,0 +1,8 @@
{%- set countryPascal = name|pascal -%}
<odoo>
<record id="l10n_{{code}}_structure_type_employee_{{code}}" model="hr.payroll.structure.type">
<field name="name">{{countryPascal}}: Employee</field>
<field name="default_resource_calendar_id" ref="resource.resource_calendar_std"/>
<field name="country_id" ref="base.{{code}}"/>
</record>
</odoo>
@@ -0,0 +1,51 @@
{%- set countryPascal = name|pascal -%}
{%- set codeUpper = code|upper -%}
<odoo>
<record id="l10n_{{code}}_rule_parameter_social_employee_rate" model="hr.rule.parameter">
<field name="name">{{countryPascal}}: Pension Contribution Employee Rate</field>
<field name="code">l10n_{{code}}_social_employee_rate</field>
<field name="country_id" ref="base.{{code}}"/>
</record>
<record id="l10n_{{code}}_rule_parameter_social_employee_rate_2023" model="hr.rule.parameter.value">
<field name="parameter_value">-9.76</field>
<field name="rule_parameter_id" ref="l10n_{{code}}_rule_parameter_social_employee_rate"/>
<field name="date_from" eval="datetime(2017, 1, 1).date()"/>
</record>
<record id="l10n_{{code}}_rule_parameter_social_employer_rate" model="hr.rule.parameter">
<field name="name">{{countryPascal}}: Pension Contribution Employer Rate</field>
<field name="code">l10n_{{code}}_social_employer_rate</field>
<field name="country_id" ref="base.{{code}}"/>
</record>
<record id="l10n_{{code}}_rule_parameter_social_employer_rate_2023" model="hr.rule.parameter.value">
<field name="parameter_value">9.76</field>
<field name="rule_parameter_id" ref="l10n_{{code}}_rule_parameter_social_employer_rate"/>
<field name="date_from" eval="datetime(2017, 1, 1).date()"/>
</record>
<record id="l10n_{{code}}_rule_parameter_tax_brackets" model="hr.rule.parameter">
<field name="name">{{countryPascal}}: Tax Brackets</field>
<field name="code">l10n_{{code}}_tax_brackets</field>
<field name="country_id" ref="base.{{code}}"/>
</record>
<record id="l10n_{{code}}_rule_parameter_tax_brackets_2023" model="hr.rule.parameter.value">
<field name="parameter_value">[
( 0, 10000, 0, 5),
(10000, 30000, 500, 10),
(30000, 'inf', 2000, 5),
]</field>
<field name="rule_parameter_id" ref="l10n_{{code}}_rule_parameter_tax_brackets"/>
<field name="date_from" eval="datetime(2017, 1, 1).date()"/>
</record>
<record id="l10n_{{code}}_rule_parameter_childcare_relief" model="hr.rule.parameter">
<field name="name">{{countryPascal}}: Chilcare Relief</field>
<field name="code">l10n_{{code}}_childcare_relief</field>
<field name="country_id" ref="base.{{code}}"/>
</record>
<record id="l10n_{{code}}_rule_parameter_childcare_relief_2023" model="hr.rule.parameter.value">
<field name="parameter_value">[92.67, 92.67, 166.67, 225]</field>
<field name="rule_parameter_id" ref="l10n_{{code}}_rule_parameter_childcare_relief"/>
<field name="date_from" eval="datetime(2017, 1, 1).date()"/>
</record>
</odoo>
@@ -0,0 +1,35 @@
{%- set countryPascal = name|pascal -%}
{%- set codeUpper = code|upper -%}
<odoo>
<record id="l10n_{{code}}_category_social_security_employee" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Social Security Employee</field>
<field name="code">SOCIAL.EMPLOYEE</field>
<field name="parent_id" ref="hr_payroll.ALW"/>
</record>
<record id="l10n_{{code}}_category_social_security_employer" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Social Security Employer</field>
<field name="code">SOCIAL.EMPLOYER</field>
</record>
<record id="l10n_{{code}}_category_social_security_employee_total" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Social Security Employee (TOTAL)</field>
<field name="code">SOCIALTOTAL.EMPLOYEE</field>
</record>
<record id="l10n_{{code}}_category_social_security_employer_total" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Social Security Employer (TOTAL)</field>
<field name="code">SOCIALTOTAL.EMPLOYER</field>
</record>
<record id="l10n_{{code}}_category_taxable_amount" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Taxable Amount</field>
<field name="code">TAXABLE</field>
</record>
<record id="l10n_{{code}}_category_withholding_taxes" model="hr.salary.rule.category">
<field name="name">{{countryPascal}}: Withholding Taxes</field>
<field name="code">TAX</field>
<field name="parent_id" ref="hr_payroll.DED"/>
</record>
</odoo>
@@ -0,0 +1,131 @@
{%- set countryPascal = name|pascal -%}
<odoo>
<!--
Sources:
government website, pwc, papayaglobal
-->
<record id="l10n_{{code}}_social_contribution" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_social_security_employee"/>
<field name="name">{{countryPascal}}: Social Contribution</field>
<field name="code">SOCIAL.EMPLOYEE</field>
<field name="sequence">50</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
result_rate = payslip.rule_parameter('l10n_{{code}}_social_employee_rate')
result = categories.BASIC
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_social_contribution_employer" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_social_security_employer"/>
<field name="name">{{countryPascal}}: Social Contribution (Employer)</field>
<field name="code">SOCIAL.EMPLOYER</field>
<field name="sequence">50</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
result_rate = payslip.rule_parameter('l10n_{{code}}_social_employer_rate')
result = categories.BASIC
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="False"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_social_employee_total" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_social_security_employee_total"/>
<field name="name">{{countryPascal}}: Social Security Total (Employee)</field>
<field name="code">SOCIAL.EMPLOYEE.TOTAL</field>
<field name="sequence">70</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
result = categories['SOCIAL.EMPLOYEE']
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="True"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_social_employer_total" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_social_security_employer_total"/>
<field name="name">{{countryPascal}}: Social Security Total (Employer)</field>
<field name="code">SOCIAL.EMPLOYER.TOTAL</field>
<field name="sequence">70</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
result = categories['SOCIAL.EMPLOYER']
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="False"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_taxable_amount" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_taxable_amount"/>
<field name="name">{{countryPascal}}: Taxable Amount</field>
<field name="code">TAXABLE</field>
<field name="sequence">115</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
result = categories.GROSS
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="True"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_withholding_taxes" model="hr.salary.rule">
<field name="category_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_category_withholding_taxes"/>
<field name="name">{{countryPascal}}: Withholding Taxes</field>
<field name="code">TAX</field>
<field name="sequence">150</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
taxable = categories.TAXABLE
brackets = payslip.rule_parameter('l10n_{{code}}_tax_brackets')
for low, high, prev, rate in brackets:
if high == 'inf':
high = float('inf')
else:
if low &lt;= taxable &lt; high:
result = -(prev + (taxable - low) * rate / 100)
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="True"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
<record id="l10n_{{code}}_childcare_relief" model="hr.salary.rule">
<field name="category_id" ref="hr_payroll.DED"/>
<field name="name">{{countryPascal}}: Childcare relief</field>
<field name="code">CHILD</field>
<field name="sequence">165</field>
<field name="condition_select">none</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
children = payslip.dict.employee_id.children
amounts = payslip.rule_parameter('l10n_{{code}}_childcare_relief')
if not children:
result = 0
elif children == 1:
result = amounts[0]
elif children == 2:
result = amounts[0] + amounts[1]
elif children == 3:
result = amounts[0] + amounts[1] + amounts[2]
elif children &gt;= 4:
result = amounts[0] + amounts[1] + amounts[2] + (children - 3) * amounts[3]
</field>
<field name="appears_on_payroll_report" eval="True"/>
<field name="appears_on_payslip" eval="True"/>
<field name="struct_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_hr_payroll_structure_{{code}}_employee_salary"/>
</record>
</odoo>
@@ -0,0 +1,147 @@
{%- set countryPascal = name|pascal -%}
{%- set codeUpper = code|upper -%}
<odoo>
<record id="l10n_{{code}}_res_company_{{code}}" model="res.company">
<field name="name">My ''country-ish'' Company</field>
<field name="currency_id" ref="base.EUR"/>
<field name="street">34A, Vilijos g.</field>
<field name="zip">02243</field>
<field name="city">Vilnius</field>
<field name="country_id" ref="base.{{code}}"/>
</record>
<record id="base.user_admin" model="res.users">
<field name="company_ids" eval="[(4, ref('l10n_{{code}}_hr_payroll.res_company_{{code}}'))]"/>
</record>
<record id="base.user_demo" model="res.users">
<field name="company_ids" eval="[(4, ref('l10n_{{code}}_hr_payroll.res_company_{{code}}'))]"/>
</record>
<record id="l10n_{{code}}_hr_department_rd{{code}}" model="hr.department">
<field name="name">RD {{codeUpper}}</field>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
</record>
<record id="l10n_{{code}}_job_developer_{{name}}" model="hr.job">
<field name="name">Experienced Developer {{codeUpper}}</field>
<field name="department_id" ref="hr_department_rd{{code}}"/>
<field name="no_of_recruitment">5</field>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
</record>
<record id="l10n_{{code}}_hr_employee_blazej" model="hr.employee">
<field name="name">Błażej Czarnecki</field>
<field name="job_id" ref="job_developer_{{name}}"/>
<field name="country_id" ref="base.{{code}}"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="gender">male</field>
</record>
<record id="l10n_{{code}}_res_partner_antonina" model="res.partner">
<field name="name">Antonina Kaczmarczyk</field>
<field name="street">Wczasowa 84A/39</field>
<field name="city">Magdalenka</field>
<field name="zip">15584</field>
<field name="country_id" ref="base.{{code}}"/>
<field name="phone">0048 025 446 527</field>
<field name="email">antonina.kaczmarczyk@example.com</field>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
</record>
<record id="l10n_{{code}}_user_antonina" model="res.users">
<field name="partner_id" ref="l10n_{{code}}_hr_payroll.res_partner_antonina"/>
<field name="login">antoninakaczmarczyk</field>
<field name="password">antoninakaczmarczyk</field>
<field name="signature" type="html"><span>--<br/>+A. Kaczmarczyk</span></field>
<field name="company_ids" eval="[(4, ref('l10n_{{code}}_hr_payroll.res_company_{{code}}'))]"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/>
</record>
<record id="l10n_{{code}}_res_partner_antonina_work_address" model="res.partner">
<field name="name">{{codeUpper}} Offices</field>
<field name="street">Bogusławskiego Wojciecha, 61/70</field>
<field name="city">Zgorzelec</field>
<field name="zip">26200</field>
<field name="country_id" ref="base.{{code}}"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
</record>
<record id="l10n_{{code}}_res_partner_antonina_private_address" model="res.partner">
<field name="name">Antonina Kaczmarczyk</field>
<field name="street">Księżycowa 14/69</field>
<field name="city">Kamienica Królewska</field>
<field name="zip">55616</field>
<field name="country_id" ref="base.{{code}}"/>
<field name="phone">0048 391 443 088</field>
<field name="email">antonina.kaczmarczyk@example.com</field>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="type">private</field>
</record>
<record id="l10n_{{code}}_res_partner_bank_account_norberta" model="res.partner.bank">
<field name="acc_number">{{codeUpper}}20002904010518489266398616</field>
<field name="bank_id" ref="base.bank_ing"/>
<field name="partner_id" ref="l10n_{{code}}_hr_payroll.res_partner_antonina_private_address"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
</record>
<record id="l10n_{{code}}_hr_employee_antonina" model="hr.employee">
<field name="name">Antonina Kaczmarczyk (fpo)</field>
<field name="gender">female</field>
<field name="marital">single</field>
<field name="job_title">Software Developer</field>
<field name="address_home_id" ref="l10n_{{code}}_hr_payroll.res_partner_antonina_private_address"/>
<field name="address_id" ref="l10n_{{code}}_hr_payroll.res_partner_antonina_work_address"/>
<field name="emergency_contact">Mariusz Kaczmarczyk</field>
<field name="emergency_phone">0048(07)4975784</field>
<field name="birthday">1991-07-28</field>
<field name="km_home_work">25</field>
<field name="place_of_birth">{{countryPascal}}</field>
<field name="country_of_birth" ref="base.{{code}}"/>
<field name="certificate">master</field>
<field name="study_field">Civil Engineering</field>
<field name="study_school">Université Catholique de Louvain-la-Neuve</field>
<field name="parent_id" ref="l10n_{{code}}_hr_payroll.hr_employee_blazej"/>
<field name="country_id" ref="base.{{code}}"/>
<field name="resource_calendar_id" ref="resource.resource_calendar_std"/>
<field name="identification_id">8752027365496</field>
<field name="bank_account_id" ref="l10n_{{code}}_hr_payroll.res_partner_bank_account_norberta"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="user_id" ref="l10n_{{code}}_hr_payroll.user_antonina"/>
</record>
<record id="l10n_{{code}}_hr_contract_cdi_antonina_previous" model="hr.contract">
<field name="name">CDI - Antonina Kaczmarczyk - Experienced Developer</field>
<field name="department_id" ref="hr_department_rd{{code}}"/>
<field name="employee_id" ref="hr_employee_antonina"/>
<field name="job_id" ref="l10n_{{code}}_hr_payroll.job_developer_{{name}}"/>
<field name="structure_type_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_structure_type_employee_{{code}}"/>
<field name="wage">3000</field>
<field name="state">close</field>
<field name="hr_responsible_id" ref="base.user_demo"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="date_start" eval="(DateTime.today() + relativedelta(years=-2, month=1, day=1))"/>
<field name="date_end" eval="(DateTime.today() + relativedelta(years=-1, month=1, day=1, days=-2))"/>
<field name="resource_calendar_id" model="resource.calendar" eval="obj().search([('company_id', '=', obj().env.ref('l10n_{{code}}_hr_payroll.res_company_{{code}}').id)], limit=1)"/>
</record>
<record id="l10n_{{code}}_hr_contract_cdi_antonina" model="hr.contract">
<field name="name">CDI - Antonina Kaczmarczyk - Experienced Developer</field>
<field name="department_id" ref="hr_department_rd{{code}}"/>
<field name="employee_id" ref="hr_employee_antonina"/>
<field name="job_id" ref="l10n_{{code}}_hr_payroll.job_developer_{{name}}"/>
<field name="structure_type_id" ref="l10n_{{code}}_hr_payroll.l10n_{{code}}_structure_type_employee_{{code}}"/>
<field name="wage">3600</field>
<field name="state">open</field>
<field name="hr_responsible_id" ref="base.user_demo"/>
<field name="company_id" ref="l10n_{{code}}_hr_payroll.res_company_{{code}}"/>
<field name="date_start" eval="(DateTime.today() + relativedelta(years=-1, month=1, day=1, days=-1))"/>
<field name="resource_calendar_id" model="resource.calendar" eval="obj().search([('company_id', '=', obj().env.ref('l10n_{{code}}_hr_payroll.res_company_{{code}}').id)], limit=1)"/>
</record>
<record id="l10n_{{code}}_hr_employee_antonina" model="hr.employee">
<field name="contract_id" ref="l10n_{{code}}_hr_payroll.hr_contract_cdi_antonina"/>
</record>
</odoo>
@@ -0,0 +1,5 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import hr_payslip
from . import hr_contract
from . import hr_payslip_worked_days
@@ -0,0 +1,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class HrContract(models.Model):
_inherit = 'hr.payslip'
l10n_{{code}}_field = fields.Char()
@@ -0,0 +1,29 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class HrPayslip(models.Model):
_inherit = 'hr.payslip'
def _get_data_files_to_update(self):
# Note: file order should be maintained
return super()._get_data_files_to_update() + [(
'l10n_{{code}}_hr_payroll', [
'data/hr_salary_rule_category_data.xml',
'data/hr_payroll_structure_type_data.xml',
'data/hr_payroll_structure_data.xml',
'data/hr_rule_parameters_data.xml',
'data/hr_salary_rule_data.xml',
])]
def _get_base_local_dict(self):
res = super()._get_base_local_dict()
res.update({
'compute_some_property': compute_some_property,
})
return res
def compute_some_property(payslip, parameter):
gross = payslip.result_rules.GROSS
return gross * parameter
@@ -0,0 +1,20 @@
{%- set codeUpper = code|upper -%}
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class HrPayslipWorkedDays(models.Model):
_inherit = 'hr.payslip.worked_days'
def _compute_amount(self):
super()._compute_amount()
for worked_day in self:
if worked_day.payslip_id.state in ['draft', 'verify'] \
and not worked_day.payslip_id.edited \
and worked_day.payslip_id.wage_type == "monthly" \
and worked_day.payslip_id.struct_id.country_id.code == "{{codeUpper}}" \
and worked_day.is_paid \
and worked_day.work_entry_type_id.code == "LEAVE110":
worked_day.amount *= 0.80
@@ -0,0 +1,16 @@
{%- set countryPascal = name|pascal -%}
<odoo>
<record id="l10n_{{code}}_action_report_payslip_{{code}}" model="ir.actions.report">
<field name="name">{{countryPascal}}: Payslip</field>
<field name="model">hr.payslip</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">l10n_{{code}}_hr_payroll.report_payslip_{{code}}_lang</field>
<field name="report_file">l10n_{{code}}_hr_payroll.report_payslip_{{code}}_lang</field>
<field name="print_report_name">'Payslip - %s' % (object.employee_id.name)</field>
<field name="binding_model_id" ref="hr_payroll.model_hr_payslip"/>
<field name="binding_type">report</field>
<!-- Erase fields to avoid double PDF posting -->
<field name="attachment"></field>
<field name="attachment_use" eval="False"/>
</record>
</odoo>
@@ -0,0 +1,14 @@
<odoo>
<template id="l10n_{{code}}_report_payslip_{{code}}" inherit_id="hr_payroll.report_payslip" primary="True">
</template>
<template id="l10n_{{code}}_report_payslip_{{code}}_lang">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-set="o" t-value="o.with_context(lang=o.employee_id.sudo().address_home_id.lang or o.env.lang)"/>
<t t-call="l10n_{{code}}_hr_payroll.report_payslip_{{code}}" t-lang="o.env.lang"/>
</t>
</t>
</template>
</odoo>