Add simple payroll structure

This commit is contained in:
metatroncubeswdev 2026-08-30 01:15:04 -04:00
parent d9d17c7521
commit 992048501a
4 changed files with 188 additions and 0 deletions

View File

@ -0,0 +1 @@
from . import hooks

View File

@ -0,0 +1,15 @@
{
"name": "Metatroncube Simple Payroll",
"version": "17.0.1.0.0",
"category": "Payroll",
"summary": "Simple monthly payroll without statutory tax, PF, or ESI deductions",
"author": "Metatroncube Software Solutions",
"license": "LGPL-3",
"depends": ["payroll"],
"data": [
"views/hr_payslip_views.xml",
],
"post_init_hook": "post_init_hook",
"installable": True,
"application": False,
}

View File

@ -0,0 +1,117 @@
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
SimplePayrollSetup(env).run()
class SimplePayrollSetup:
def __init__(self, env):
self.env = env
self.Category = env["hr.salary.rule.category"]
self.Rule = env["hr.salary.rule"]
self.Structure = env["hr.payroll.structure"]
self.Contract = env["hr.contract"]
self.Company = env["res.company"]
def run(self):
categories = self._ensure_categories()
for company in self.Company.search([]):
structure = self._ensure_structure(company, categories)
self._assign_open_contracts(company, structure)
def _ensure_categories(self):
specs = [
("BASIC", "Basic"),
("GROSS", "Gross"),
("NET", "Net"),
]
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_rule(self, company, code, name, sequence, category, python_code):
rule = self.Rule.search(
[
("code", "=", code),
("company_id", "=", company.id),
("name", "=", name),
],
limit=1,
)
values = {
"name": name,
"code": code,
"sequence": sequence,
"category_id": category.id,
"company_id": company.id,
"condition_select": "none",
"amount_select": "code",
"amount_python_compute": python_code.strip(),
"appears_on_payslip": True,
"active": True,
}
if rule:
rule.write(values)
else:
rule = self.Rule.create(values)
return rule
def _ensure_structure(self, company, categories):
basic = self._ensure_rule(
company,
"MCS_BASIC",
"Basic Salary",
10,
categories["BASIC"],
"result = contract.wage",
)
gross = self._ensure_rule(
company,
"MCS_GROSS",
"Gross Salary",
100,
categories["GROSS"],
"result = categories.BASIC",
)
net = self._ensure_rule(
company,
"MCS_NET",
"Net Salary",
200,
categories["NET"],
"result = categories.GROSS",
)
structure = self.Structure.search(
[("code", "=", "MCS_SIMPLE_MONTHLY"), ("company_id", "=", company.id)],
limit=1,
)
values = {
"name": "MCS Simple Monthly Payroll",
"code": "MCS_SIMPLE_MONTHLY",
"company_id": company.id,
"rule_ids": [(6, 0, [basic.id, gross.id, net.id])],
}
if structure:
structure.write(values)
else:
structure = self.Structure.create(values)
return structure
def _assign_open_contracts(self, company, structure):
contracts = self.Contract.search(
[
("company_id", "=", company.id),
("state", "=", "open"),
("employee_id.active", "=", True),
]
)
contracts.write({"struct_id": structure.id, "schedule_pay": "monthly"})

View File

@ -0,0 +1,55 @@
<odoo>
<template id="report_payslip_simple" inherit_id="payroll.report_payslip">
<xpath expr="//div[hasclass('page')]" position="replace">
<div class="page">
<h2>Salary Payslip</h2>
<table class="table table-sm table-bordered">
<tr>
<td><strong>Employee</strong></td>
<td><span t-field="o.employee_id"/></td>
<td><strong>Job Title</strong></td>
<td><span t-field="o.employee_id.job_title"/></td>
</tr>
<tr>
<td><strong>Email</strong></td>
<td><span t-field="o.employee_id.work_email"/></td>
<td><strong>Payslip Ref</strong></td>
<td><span t-field="o.number"/></td>
</tr>
<tr>
<td><strong>Period From</strong></td>
<td><span t-field="o.date_from"/></td>
<td><strong>Period To</strong></td>
<td><span t-field="o.date_to"/></td>
</tr>
<tr>
<td><strong>Structure</strong></td>
<td><span t-field="o.struct_id"/></td>
<td><strong>Bank Account</strong></td>
<td><span t-field="o.employee_id.bank_account_id"/></td>
</tr>
</table>
<table class="table table-sm table-bordered">
<thead>
<tr>
<th>Description</th>
<th class="text-end">Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.line_ids.filtered(lambda l: l.appears_on_payslip and l.amount != 0)" t-as="line">
<td><span t-field="line.name"/></td>
<td class="text-end">
<span t-esc="line.total" t-options='{"widget": "monetary", "display_currency": o.company_id.currency_id}'/>
</td>
</tr>
</tbody>
</table>
<p>This payslip is generated for internal salary processing only. No statutory tax, PF, or ESI deductions are applied in the simple payroll structure.</p>
<p class="text-end"><strong>Authorized signature</strong></p>
</div>
</xpath>
</template>
</odoo>