From d7df1856fa25bc940260f1f4f4c37c856bf8fb4b Mon Sep 17 00:00:00 2001 From: dasz Date: Mon, 15 May 2023 15:17:49 +0000 Subject: [PATCH] [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 --- odoo/cli/scaffold.py | 16 +- .../l10n_payroll/__init__.py.template | 3 + .../l10n_payroll/__manifest__.py.template | 36 +++++ .../hr_payroll_structure_data.xml.template | 14 ++ ...r_payroll_structure_type_data.xml.template | 8 + .../data/hr_rule_parameters_data.xml.template | 51 ++++++ .../hr_salary_rule_category_data.xml.template | 35 +++++ .../data/hr_salary_rule_data.xml.template | 131 ++++++++++++++++ ...l10n_{{code}}_hr_payroll_demo.xml.template | 147 ++++++++++++++++++ .../l10n_payroll/models/__init__.py.template | 5 + .../models/hr_contract.py.template | 9 ++ .../models/hr_payslip.py.template | 29 ++++ .../models/hr_payslip_worked_days.py.template | 20 +++ .../views/hr_payroll_report.xml.template | 16 ++ .../report_payslip_templates.xml.template | 14 ++ 15 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 odoo/cli/templates/l10n_payroll/__init__.py.template create mode 100644 odoo/cli/templates/l10n_payroll/__manifest__.py.template create mode 100644 odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_data.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_type_data.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/data/hr_rule_parameters_data.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/data/hr_salary_rule_category_data.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/data/hr_salary_rule_data.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/data/l10n_{{code}}_hr_payroll_demo.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/models/__init__.py.template create mode 100644 odoo/cli/templates/l10n_payroll/models/hr_contract.py.template create mode 100644 odoo/cli/templates/l10n_payroll/models/hr_payslip.py.template create mode 100644 odoo/cli/templates/l10n_payroll/models/hr_payslip_worked_days.py.template create mode 100644 odoo/cli/templates/l10n_payroll/views/hr_payroll_report.xml.template create mode 100644 odoo/cli/templates/l10n_payroll/views/report_payslip_templates.xml.template diff --git a/odoo/cli/scaffold.py b/odoo/cli/scaffold.py index ea861dffec1..aa1fdac629a 100644 --- a/odoo/cli/scaffold.py +++ b/odoo/cli/scaffold.py @@ -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) diff --git a/odoo/cli/templates/l10n_payroll/__init__.py.template b/odoo/cli/templates/l10n_payroll/__init__.py.template new file mode 100644 index 00000000000..d6210b1285d --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/__init__.py.template @@ -0,0 +1,3 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/odoo/cli/templates/l10n_payroll/__manifest__.py.template b/odoo/cli/templates/l10n_payroll/__manifest__.py.template new file mode 100644 index 00000000000..741c03f432b --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/__manifest__.py.template @@ -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', +} diff --git a/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_data.xml.template b/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_data.xml.template new file mode 100644 index 00000000000..064bdaa3731 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_data.xml.template @@ -0,0 +1,14 @@ +{%- set countryPascal = name|pascal -%} +{%- set codeUpper = code|upper -%} + + + {{countryPascal}}: Regular Pay + {{codeUpper}}MONTHLY + + + + + + + + diff --git a/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_type_data.xml.template b/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_type_data.xml.template new file mode 100644 index 00000000000..0856aa42e19 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/hr_payroll_structure_type_data.xml.template @@ -0,0 +1,8 @@ +{%- set countryPascal = name|pascal -%} + + + {{countryPascal}}: Employee + + + + diff --git a/odoo/cli/templates/l10n_payroll/data/hr_rule_parameters_data.xml.template b/odoo/cli/templates/l10n_payroll/data/hr_rule_parameters_data.xml.template new file mode 100644 index 00000000000..b26fd8dd778 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/hr_rule_parameters_data.xml.template @@ -0,0 +1,51 @@ +{%- set countryPascal = name|pascal -%} +{%- set codeUpper = code|upper -%} + + + {{countryPascal}}: Pension Contribution Employee Rate + l10n_{{code}}_social_employee_rate + + + + -9.76 + + + + + + {{countryPascal}}: Pension Contribution Employer Rate + l10n_{{code}}_social_employer_rate + + + + 9.76 + + + + + + {{countryPascal}}: Tax Brackets + l10n_{{code}}_tax_brackets + + + + [ + ( 0, 10000, 0, 5), + (10000, 30000, 500, 10), + (30000, 'inf', 2000, 5), + ] + + + + + + {{countryPascal}}: Chilcare Relief + l10n_{{code}}_childcare_relief + + + + [92.67, 92.67, 166.67, 225] + + + + diff --git a/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_category_data.xml.template b/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_category_data.xml.template new file mode 100644 index 00000000000..f29a8d78e1a --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_category_data.xml.template @@ -0,0 +1,35 @@ +{%- set countryPascal = name|pascal -%} +{%- set codeUpper = code|upper -%} + + + {{countryPascal}}: Social Security Employee + SOCIAL.EMPLOYEE + + + + + {{countryPascal}}: Social Security Employer + SOCIAL.EMPLOYER + + + + {{countryPascal}}: Social Security Employee (TOTAL) + SOCIALTOTAL.EMPLOYEE + + + + {{countryPascal}}: Social Security Employer (TOTAL) + SOCIALTOTAL.EMPLOYER + + + + {{countryPascal}}: Taxable Amount + TAXABLE + + + + {{countryPascal}}: Withholding Taxes + TAX + + + diff --git a/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_data.xml.template b/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_data.xml.template new file mode 100644 index 00000000000..185a9971d61 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/hr_salary_rule_data.xml.template @@ -0,0 +1,131 @@ +{%- set countryPascal = name|pascal -%} + + + + + {{countryPascal}}: Social Contribution + SOCIAL.EMPLOYEE + 50 + none + code + +result_rate = payslip.rule_parameter('l10n_{{code}}_social_employee_rate') +result = categories.BASIC + + + + + + + + {{countryPascal}}: Social Contribution (Employer) + SOCIAL.EMPLOYER + 50 + none + code + +result_rate = payslip.rule_parameter('l10n_{{code}}_social_employer_rate') +result = categories.BASIC + + + + + + + + + {{countryPascal}}: Social Security Total (Employee) + SOCIAL.EMPLOYEE.TOTAL + 70 + none + code + +result = categories['SOCIAL.EMPLOYEE'] + + + + + + + + + {{countryPascal}}: Social Security Total (Employer) + SOCIAL.EMPLOYER.TOTAL + 70 + none + code + +result = categories['SOCIAL.EMPLOYER'] + + + + + + + + + {{countryPascal}}: Taxable Amount + TAXABLE + 115 + none + code + +result = categories.GROSS + + + + + + + + + {{countryPascal}}: Withholding Taxes + TAX + 150 + none + code + +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 <= taxable < high: + result = -(prev + (taxable - low) * rate / 100) + + + + + + + + + {{countryPascal}}: Childcare relief + CHILD + 165 + none + code + +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 >= 4: + result = amounts[0] + amounts[1] + amounts[2] + (children - 3) * amounts[3] + + + + + + + diff --git a/odoo/cli/templates/l10n_payroll/data/l10n_{{code}}_hr_payroll_demo.xml.template b/odoo/cli/templates/l10n_payroll/data/l10n_{{code}}_hr_payroll_demo.xml.template new file mode 100644 index 00000000000..9ff8c38274d --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/data/l10n_{{code}}_hr_payroll_demo.xml.template @@ -0,0 +1,147 @@ +{%- set countryPascal = name|pascal -%} +{%- set codeUpper = code|upper -%} + + + My ''country-ish'' Company + + 34A, Vilijos g. + 02243 + Vilnius + + + + + + + + + + + + + RD {{codeUpper}} + + + + + Experienced Developer {{codeUpper}} + + 5 + + + + + Błażej Czarnecki + + + + male + + + + Antonina Kaczmarczyk + Wczasowa 84A/39 + Magdalenka + 15584 + + 0048 025 446 527 + antonina.kaczmarczyk@example.com + + + + + + antoninakaczmarczyk + antoninakaczmarczyk + --
+A. Kaczmarczyk
+ + + +
+ + + {{codeUpper}} Offices + Bogusławskiego Wojciecha, 61/70 + Zgorzelec + 26200 + + + + + + Antonina Kaczmarczyk + Księżycowa 14/69 + Kamienica Królewska + 55616 + + 0048 391 443 088 + antonina.kaczmarczyk@example.com + + private + + + + {{codeUpper}}20002904010518489266398616 + + + + + + + Antonina Kaczmarczyk (fpo) + female + single + Software Developer + + + Mariusz Kaczmarczyk + 0048(07)4975784 + 1991-07-28 + 25 + {{countryPascal}} + + master + Civil Engineering + Université Catholique de Louvain-la-Neuve + + + + 8752027365496 + + + + + + + CDI - Antonina Kaczmarczyk - Experienced Developer + + + + + 3000 + close + + + + + + + + + CDI - Antonina Kaczmarczyk - Experienced Developer + + + + + 3600 + open + + + + + + + + + +
diff --git a/odoo/cli/templates/l10n_payroll/models/__init__.py.template b/odoo/cli/templates/l10n_payroll/models/__init__.py.template new file mode 100644 index 00000000000..01172209c03 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/models/__init__.py.template @@ -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 diff --git a/odoo/cli/templates/l10n_payroll/models/hr_contract.py.template b/odoo/cli/templates/l10n_payroll/models/hr_contract.py.template new file mode 100644 index 00000000000..74a347136c6 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/models/hr_contract.py.template @@ -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() diff --git a/odoo/cli/templates/l10n_payroll/models/hr_payslip.py.template b/odoo/cli/templates/l10n_payroll/models/hr_payslip.py.template new file mode 100644 index 00000000000..cc1f868290a --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/models/hr_payslip.py.template @@ -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 diff --git a/odoo/cli/templates/l10n_payroll/models/hr_payslip_worked_days.py.template b/odoo/cli/templates/l10n_payroll/models/hr_payslip_worked_days.py.template new file mode 100644 index 00000000000..0530d60fda2 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/models/hr_payslip_worked_days.py.template @@ -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 diff --git a/odoo/cli/templates/l10n_payroll/views/hr_payroll_report.xml.template b/odoo/cli/templates/l10n_payroll/views/hr_payroll_report.xml.template new file mode 100644 index 00000000000..8440b4a83a7 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/views/hr_payroll_report.xml.template @@ -0,0 +1,16 @@ +{%- set countryPascal = name|pascal -%} + + + {{countryPascal}}: Payslip + hr.payslip + qweb-pdf + l10n_{{code}}_hr_payroll.report_payslip_{{code}}_lang + l10n_{{code}}_hr_payroll.report_payslip_{{code}}_lang + 'Payslip - %s' % (object.employee_id.name) + + report + + + + + diff --git a/odoo/cli/templates/l10n_payroll/views/report_payslip_templates.xml.template b/odoo/cli/templates/l10n_payroll/views/report_payslip_templates.xml.template new file mode 100644 index 00000000000..4bbc2952c51 --- /dev/null +++ b/odoo/cli/templates/l10n_payroll/views/report_payslip_templates.xml.template @@ -0,0 +1,14 @@ + + + + +