209 lines
7.8 KiB
Python
209 lines
7.8 KiB
Python
from odoo import api, SUPERUSER_ID
|
|
|
|
|
|
def post_init_hook(env_or_cr, registry=None):
|
|
if registry is not None:
|
|
env = api.Environment(env_or_cr, SUPERUSER_ID, {})
|
|
else:
|
|
env = env_or_cr
|
|
PayrollSetup(env).run()
|
|
|
|
|
|
class PayrollSetup:
|
|
def __init__(self, env):
|
|
self.env = env
|
|
self.Category = env["hr.salary.rule.category"]
|
|
self.Register = env["hr.contribution.register"]
|
|
self.Rule = env["hr.salary.rule"]
|
|
self.RuleInput = env["hr.rule.input"]
|
|
self.Structure = env["hr.payroll.structure"]
|
|
self.Company = env["res.company"]
|
|
|
|
def run(self):
|
|
categories = self._ensure_categories()
|
|
for company in self.Company.search([("country_id.code", "=", "IN")]):
|
|
self._ensure_india(company, categories)
|
|
for company in self.Company.search([("country_id.code", "=", "CA")]):
|
|
self._ensure_canada(company, categories)
|
|
|
|
def _ensure_categories(self):
|
|
specs = [
|
|
("BASIC", "Basic"),
|
|
("ALW", "Allowance"),
|
|
("GROSS", "Gross"),
|
|
("DED", "Deduction"),
|
|
("NET", "Net"),
|
|
("COMP", "Company Contribution"),
|
|
]
|
|
result = {}
|
|
for code, name in specs:
|
|
category = self.Category.search([("code", "=", code)], limit=1)
|
|
if not category:
|
|
category = self.Category.create({"code": code, "name": name})
|
|
result[code] = category
|
|
return result
|
|
|
|
def _ensure_register(self, name):
|
|
register = self.Register.search([("name", "=", name)], limit=1)
|
|
if not register:
|
|
register = self.Register.create({"name": name})
|
|
return register
|
|
|
|
def _ensure_base_structure(self, company, categories):
|
|
base = self.Structure.search([("code", "=", "BASE"), ("company_id", "=", company.id)], limit=1)
|
|
if not base:
|
|
base = self.Structure.create({
|
|
"name": "Base Payroll Structure",
|
|
"code": "BASE",
|
|
"company_id": company.id,
|
|
"rule_ids": [(6, 0, [
|
|
self._rule(company, "Base Basic Salary", "BASE_BASIC", 10, categories["BASIC"], """
|
|
result = contract.wage
|
|
""").id,
|
|
self._rule(company, "Base Gross", "BASE_GROSS", 100, categories["GROSS"], """
|
|
result = categories.BASIC + categories.ALW
|
|
""").id,
|
|
self._rule(company, "Base Net Salary", "BASE_NET", 300, categories["NET"], """
|
|
result = categories.BASIC + categories.ALW + categories.DED
|
|
""").id,
|
|
])],
|
|
})
|
|
return base
|
|
|
|
def _rule(self, company, name, code, sequence, category, python, register=False):
|
|
domain = [("code", "=", code)]
|
|
domain.append(("company_id", "=", company.id if company else False))
|
|
rule = self.Rule.search(domain, limit=1)
|
|
values = {
|
|
"name": name,
|
|
"code": code,
|
|
"sequence": sequence,
|
|
"category_id": category.id,
|
|
"company_id": company.id if company else False,
|
|
"condition_select": "none",
|
|
"amount_select": "code",
|
|
"amount_python_compute": python.strip(),
|
|
"appears_on_payslip": True,
|
|
}
|
|
if register:
|
|
values["register_id"] = register.id
|
|
if rule:
|
|
rule.write(values)
|
|
else:
|
|
rule = self.Rule.create(values)
|
|
return rule
|
|
|
|
def _input(self, rule, code, name):
|
|
item = self.RuleInput.search([("input_id", "=", rule.id), ("code", "=", code)], limit=1)
|
|
if not item:
|
|
item = self.RuleInput.create({"input_id": rule.id, "code": code, "name": name})
|
|
return item
|
|
|
|
def _structure(self, company, code, name, rules):
|
|
base = self._ensure_base_structure(company, self._ensure_categories())
|
|
structure = self.Structure.search([("code", "=", code), ("company_id", "=", company.id)], limit=1)
|
|
values = {
|
|
"name": name,
|
|
"code": code,
|
|
"company_id": company.id,
|
|
"parent_id": base.id,
|
|
"rule_ids": [(6, 0, [rule.id for rule in rules])],
|
|
}
|
|
if structure:
|
|
structure.write(values)
|
|
else:
|
|
structure = self.Structure.create(values)
|
|
return structure
|
|
|
|
def _ensure_india(self, company, categories):
|
|
pf = self._ensure_register("India Employees Provident Fund")
|
|
esi = self._ensure_register("India Employees State Insurance")
|
|
tax = self._ensure_register("India Payroll Tax Deductions")
|
|
rules = [
|
|
self._rule(company, "Basic Salary", "BASIC", 10, categories["BASIC"], """
|
|
result = contract.wage * 0.50
|
|
"""),
|
|
self._rule(company, "House Rent Allowance", "HRA", 20, categories["ALW"], """
|
|
result = contract.wage * 0.20
|
|
"""),
|
|
self._rule(company, "Special Allowance", "ALLOW", 30, categories["ALW"], """
|
|
result = contract.wage - categories.BASIC - categories.ALW
|
|
"""),
|
|
self._rule(company, "Gross", "GROSS", 100, categories["GROSS"], """
|
|
result = categories.BASIC + categories.ALW
|
|
"""),
|
|
self._rule(company, "Employee Provident Fund", "EPF", 150, categories["DED"], """
|
|
base = categories.BASIC
|
|
if base > 15000.0:
|
|
base = 15000.0
|
|
result = -(base * 0.12)
|
|
""", pf),
|
|
self._rule(company, "Employee State Insurance", "ESI", 160, categories["DED"], """
|
|
result = 0.0
|
|
if categories.GROSS <= 21000.0:
|
|
result = -(categories.GROSS * 0.0075)
|
|
""", esi),
|
|
self._rule(company, "Professional Tax", "IN_PT", 170, categories["DED"], """
|
|
result = -(inputs.IN_PT.amount) if inputs.IN_PT else 0.0
|
|
""", tax),
|
|
self._rule(company, "Income Tax TDS", "IN_TDS", 180, categories["DED"], """
|
|
result = -(inputs.IN_TDS.amount) if inputs.IN_TDS else 0.0
|
|
""", tax),
|
|
self._rule(company, "Net Salary", "NET", 300, categories["NET"], """
|
|
result = categories.BASIC + categories.ALW + categories.DED
|
|
"""),
|
|
]
|
|
self._input(rules[6], "IN_PT", "Professional Tax")
|
|
self._input(rules[7], "IN_TDS", "Income Tax TDS")
|
|
self._structure(company, "MCS_IN_PAYROLL", "India Monthly Payroll", rules)
|
|
|
|
def _ensure_canada(self, company, categories):
|
|
cpp = self._ensure_register("Canada Pension Plan")
|
|
ei = self._ensure_register("Employment Insurance")
|
|
tax = self._ensure_register("Canada Payroll Tax Deductions")
|
|
rules = [
|
|
self._rule(company, "Regular Salary", "BASIC", 10, categories["BASIC"], """
|
|
result = contract.wage
|
|
"""),
|
|
self._rule(company, "Gross", "GROSS", 100, categories["GROSS"], """
|
|
result = categories.BASIC + categories.ALW
|
|
"""),
|
|
self._rule(company, "CPP Employee Contribution", "CPP", 150, categories["DED"], """
|
|
monthly_exemption = 3500.0 / 12.0
|
|
monthly_max = 74600.0 / 12.0
|
|
base = categories.GROSS
|
|
if base > monthly_max:
|
|
base = monthly_max
|
|
base = base - monthly_exemption
|
|
if base < 0.0:
|
|
base = 0.0
|
|
result = -(base * 0.0595)
|
|
""", cpp),
|
|
self._rule(company, "CPP2 Employee Contribution", "CPP2", 155, categories["DED"], """
|
|
lower = 74600.0 / 12.0
|
|
upper = 85000.0 / 12.0
|
|
base = categories.GROSS
|
|
if base < lower:
|
|
base = lower
|
|
if base > upper:
|
|
base = upper
|
|
base = base - lower
|
|
result = -(base * 0.04)
|
|
""", cpp),
|
|
self._rule(company, "Employment Insurance", "EI", 160, categories["DED"], """
|
|
monthly_max = 68900.0 / 12.0
|
|
base = categories.GROSS
|
|
if base > monthly_max:
|
|
base = monthly_max
|
|
result = -(base * 0.0163)
|
|
""", ei),
|
|
self._rule(company, "Federal and Ontario Income Tax", "CA_TAX", 180, categories["DED"], """
|
|
result = -(inputs.CA_TAX.amount) if inputs.CA_TAX else 0.0
|
|
""", tax),
|
|
self._rule(company, "Net Salary", "NET", 300, categories["NET"], """
|
|
result = categories.BASIC + categories.ALW + categories.DED
|
|
"""),
|
|
]
|
|
self._input(rules[5], "CA_TAX", "Federal and Ontario Income Tax")
|
|
self._structure(company, "MCS_CA_PAYROLL", "Canada Monthly Payroll", rules)
|