employee it declartion module

This commit is contained in:
Pranay 2025-12-22 10:59:35 +05:30
parent 4061ba226f
commit 33fbe0ebe2
33 changed files with 3797 additions and 0 deletions

View File

@ -0,0 +1,2 @@
from . import models
from . import wizards

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
{
'name': "Payroll Tax Management",
'summary': "Manage Income Tax Declarations for Employees in Payroll",
'description': """
Payroll IT Declarations
========================
This module allows HR and payroll departments to manage and track Income Tax (IT) declarations submitted by employees.
Features:
---------
- Employee-wise tax declaration submission
- HR approval workflow for declarations
- Category-wise declaration limits (e.g. 80C, HRA, LTA, etc.)
- Auto-calculation of eligible deductions
- Integration with Odoo Payroll for accurate tax computation
- Attach supporting documents (PDFs, images)
- Employee self-service through portal
Built with usability and compliance in mind, this module streamlines the IT declaration process and ensures transparency and efficiency across the organization.
Developed by: Pranay
""",
'author': "Pranay",
'website': "https://www.ftprotech.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml
# for the full list
'category': 'Human Resources',
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base','hr','hr_payroll','hr_employee_extended'],
# always loaded
'data': [
'security/ir.model.access.csv',
'views/payroll_periods.xml',
'views/investment_types.xml',
# 'views/payroll_periods.xml',
'views/slab_master.xml',
'views/emp_it_declaration.xml',
'views/report_it_tax_statement.xml',
'report/report_action.xml',
'report/it_tax_template.xml',
'views/it_tax_menu_and_wizard_view.xml',
'wizards/children_education_costing.xml',
'wizards/employee_life_insurance.xml',
'wizards/nsc_declaration.xml',
'wizards/self_occupied_property.xml',
'wizards/letout_house_property.xml',
'wizards/nsc_income_loss.xml',
# 'views/it_investment_type.xml',
# 'views/it_investment_costing.xml'
],
}

View File

@ -0,0 +1,7 @@
from . import payroll_periods
from . import investment_types
from . import investment_costings
from . import emp_it_declaration
from . import slab_master
from . import it_tax_statement
from . import it_tax_statement_wiz

View File

@ -0,0 +1,274 @@
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
import calendar
class EmpITDeclaration(models.Model):
_name = 'emp.it.declaration'
_rec_name = 'employee_id'
_description = "IT Declaration"
# @api.depends('period_id', 'employee_id')
# def _compute_name(self):
# for sheet in self:
# # sheet.name = _('%(period_id)s, %(emp_name)s', period_id=sheet.period_id.name, emp_name=sheet.employee_id.name)
# sheet.name='hello world'
employee_id = fields.Many2one(
'hr.employee',
string="Employee",
default=lambda self: self.env.user.employee_id,
required=True
)
period_id = fields.Many2one(
'payroll.period',
string="Payroll Period",
required=True
)
display_period_label = fields.Char(string="Period Label", compute='_compute_display_period_label')
@api.depends('period_id.name')
def _compute_display_period_label(self):
for rec in self:
if rec.period_id:
rec.display_period_label = f"Financial Year {rec.period_id.name}"
else:
rec.display_period_label = ""
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime')
], string="Tax Regime", required=True, default='new')
total_investment = fields.Float(string='Total Investment')
costing_details_generated = fields.Boolean(default=False)
investment_costing_ids = fields.One2many('investment.costings','it_declaration_id')
house_rent_costing_id = fields.Many2one('investment.costings', compute="_compute_investment_costing")
is_section_open = fields.Boolean()
@api.depends('costing_details_generated','investment_costing_ids')
def _compute_investment_costing(self):
for rec in self:
if rec.investment_costing_ids and rec.costing_details_generated:
rec.house_rent_costing_id = rec.investment_costing_ids.filtered(
lambda e: e.investment_type_id.investment_type == 'house_rent'
)[:1]
else:
rec.house_rent_costing_id = False
past_employment_costings = fields.One2many('past_employment.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['old', 'both'])])
past_employment_costings_new = fields.One2many('past_employment.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['new', 'both'])])
us80c_costings = fields.One2many('us80c.costing.type','it_declaration_id')
us80d_selection_type = fields.Selection([('self_family','Self-family'),('self_family_parent','Self-family and parent'),('self_family_senior_parent','Self-family and senior parent')], default='self_family',required=True)
us80d_health_checkup = fields.Boolean(string='Preventive Health Checkup')
us80d_costings = fields.One2many('us80d.costing.type','it_declaration_id',domain=[('investment_type_line_id.for_family','=',True),('investment_type_line_id.for_parents','=',False),('investment_type_line_id.for_senior_parent','=',False)])
us80d_costings_parents = fields.One2many('us80d.costing.type','it_declaration_id',domain=['|',('investment_type_line_id.for_family','=',True),('investment_type_line_id.for_parents','=',True),('investment_type_line_id.for_senior_parent','=',False)])
us80d_costings_senior_parents = fields.One2many('us80d.costing.type','it_declaration_id',domain=['|','|',('investment_type_line_id.for_family','=',True),('investment_type_line_id.for_parents','=',True),('investment_type_line_id.for_senior_parent','=',True)])
us10_costings = fields.One2many('us10.costing.type','it_declaration_id')
us80g_costings = fields.One2many('us80g.costing.type','it_declaration_id')
chapter_via_costings = fields.One2many('chapter.via.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['old', 'both'])])
chapter_via_costings_new = fields.One2many('chapter.via.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['new', 'both'])])
us17_costings = fields.One2many('us17.costing.type','it_declaration_id')
house_rent_costings = fields.One2many('house.rent.declaration','it_declaration_id')
other_il_costings = fields.One2many('other.il.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['old', 'both'])])
other_il_costings_new = fields.One2many('other.il.costing.type','it_declaration_id',domain=[('investment_type_line_id.tax_regime', 'in', ['new', 'both'])])
other_declaration_costings = fields.One2many('other.declaration.costing.type','it_declaration_id')
def toggle_section_visibility(self):
for rec in self:
rec.is_section_open = not rec.is_section_open
if rec.is_section_open:
for investment_type in rec.investment_costing_ids:
if investment_type.investment_type_id.investment_type == 'past_employment':
if rec.tax_regime == 'old':
investment_type.amount = sum(
cost.declaration_amount
for cost in rec.past_employment_costings
if not cost.investment_type_line_id.compute_method
)
else:
investment_type.amount = sum(
cost.declaration_amount
for cost in rec.past_employment_costings_new
if not cost.investment_type_line_id.compute_method
)
elif investment_type.investment_type_id.investment_type == 'us_80c':
investment_type.amount = sum(
cost.declaration_amount
for cost in rec.us80c_costings
if not cost.investment_type_line_id.compute_method
) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'us_80d':
if rec.us80d_selection_type == 'self_family':
investment_type.amount = sum(rec.us80d_costings.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
if rec.us80d_selection_type == 'self_family_parent':
investment_type.amount = sum(rec.us80d_costings_parents.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
if rec.us80d_selection_type == 'self_family_senior_parent':
investment_type.amount = sum(rec.us80d_costings_senior_parents.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'us_10':
investment_type.amount = sum(rec.us10_costings.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'us_80g':
investment_type.amount = sum(rec.us80g_costings.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'chapter_via':
if rec.tax_regime == 'old':
investment_type.amount = sum(rec.chapter_via_costings.mapped('declaration_amount') or [0])
else:
investment_type.amount = sum(rec.chapter_via_costings_new.mapped('declaration_amount') or [0])
elif investment_type.investment_type_id.investment_type == 'us_17':
investment_type.amount = sum(rec.us17_costings.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'house_rent':
investment_type.amount = sum(rec.house_rent_costings.mapped('rent_amount') or [0]) if rec.tax_regime == 'old' else 0
elif investment_type.investment_type_id.investment_type == 'other_i_or_l':
if rec.tax_regime == 'old':
investment_type.amount = sum(rec.other_il_costings.mapped('declaration_amount') or [0])
else:
investment_type.amount = sum(rec.other_il_costings_new.mapped('declaration_amount') or [0])
elif investment_type.investment_type_id.investment_type == 'other_declaration':
investment_type.amount = sum(rec.other_declaration_costings.mapped('declaration_amount') or [0]) if rec.tax_regime == 'old' else 0
@api.onchange('tax_regime')
def _onchange_tax_regime(self):
if self.tax_regime:
# res = super(empITDeclaration, self).fields_get(allfields, attributes)
# self.fields_get()
if self.tax_regime == 'new':
domain = [('investment_type_line_id.tax_regime', 'in', ['new', 'both'])]
elif self.tax_regime == 'old':
domain = [('investment_type_line_id.tax_regime', 'in', ['old', 'both'])]
else:
domain = [] # Default case, although 'tax_regime' is required
return {'domain': {'past_employment_costings': domain}}
else:
return {'domain': {'past_employment_costings': []}} # Handle potential empty state
# def fields_get(self, allfields=None, attributes=None):
# import pdb
# pdb.set_trace()
# res = super(empITDeclaration, self).fields_get(allfields, attributes)
# print(res)
#
# # Example: Modify domain of field_1 based on field_2
# if 'tax_regime' in res:
# if self.tax_regime == '':
# res['field_1']['domain'] = [('some_field', '=', 123)]
# else:
# res['field_1']['domain'] = [('some_field', '=', 456)]
#
# return res
# import pdb
# pdb.set_trace()
# if rec.tax_regime:
# return {'domain': {'past_employment_costings': [('investment_type_line_id.tax_regime', 'in', ['new','both'])]}}
# return {
# 'domain': {
# 'past_employment_costings': [('investment_type_line_id.tax_regime', 'in', ['new','both'])]
# }
# }
def generate_declarations(self):
for rec in self:
investment_types = self.env['it.investment.type'].sudo().search([])
for inv_type in investment_types:
investment_costing = self.env['investment.costings'].sudo().create({
'investment_type_id': inv_type.id,
'it_declaration_id': rec.id,
})
if inv_type.investment_type == 'past_employment':
past_emp_costing_ids = [
self.env['past_employment.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.past_employment_ids
]
if inv_type.investment_type == 'us_80c':
us80c_costing_ids = [
self.env['us80c.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.us80c_ids
]
if inv_type.investment_type == 'us_80d':
us80d_costing_ids = [
self.env['us80d.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.us80d_ids
]
if inv_type.investment_type == 'us_10':
us10_costing_ids = [
self.env['us10.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.us10_ids
]
if inv_type.investment_type == 'us_80g':
us80g_costing_ids = [
self.env['us80g.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.us80g_ids
]
if inv_type.investment_type == 'chapter_via':
chapter_via_ids = [
self.env['chapter.via.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.chapter_via_ids
]
if inv_type.investment_type == 'us_17':
us17_costing_ids = [
self.env['us17.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.us17_ids
]
if inv_type.investment_type == 'other_i_or_l':
other_il_costing_ids = [
self.env['other.il.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.other_il_ids
]
if inv_type.investment_type == 'other_declaration':
other_declaration_costing_ids = [
self.env['other.declaration.costing.type'].sudo().create({
'costing_type': investment_costing.id,
'it_declaration_id': rec.id,
'investment_type_line_id': investment_line.id,
'limit': investment_line.limit
}).id
for investment_line in inv_type.other_declaration_ids
]
rec.costing_details_generated = True

View File

@ -0,0 +1,309 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
import calendar
import re
class investmentCostings(models.Model):
_name = 'investment.costings'
_rec_name = 'investment_type_id'
investment_type_id = fields.Many2one('it.investment.type')
amount = fields.Integer()
it_declaration_id = fields.Many2one('emp.it.declaration')
employee_id = fields.Many2one(
'hr.employee',
string="Employee",
related='it_declaration_id.employee_id'
)
period_id = fields.Many2one(
'payroll.period',
string="Payroll Period",
related='it_declaration_id.period_id'
)
class pastEmpcostingType(models.Model):
_name = 'past_employment.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
investment_type_line_id = fields.Many2one('past_employment.investment.type')
declaration_amount = fields.Integer(string='Declaration Amount',compute='_compute_declaration_amount',store=True,readonly=False)
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
@api.depends(
'it_declaration_id.past_employment_costings.declaration_amount',
'it_declaration_id.past_employment_costings_new.declaration_amount',
'investment_type_line_id.compute_method',
'investment_type_line_id.compute_code',
'it_declaration_id.tax_regime',
'declaration_amount'
)
def _compute_declaration_amount(self):
for rec in self:
line = rec.investment_type_line_id
if not line or not rec.it_declaration_id:
rec.declaration_amount = 0
continue
if line.compute_method and line.compute_code:
siblings = (
rec.it_declaration_id.past_employment_costings
if rec.it_declaration_id.tax_regime == 'old'
else rec.it_declaration_id.past_employment_costings_new
)
code_vars = {}
for sibling in siblings:
code = sibling.investment_type_line_id.investment_code
if code:
code_vars[code] = sibling.declaration_amount or 0
try:
# Extract variable names from compute_code
var_names = set(re.findall(r'\b[A-Z]+\b', line.compute_code))
for var in var_names:
code_vars.setdefault(var, 0) # Ensure missing variables default to 0
rec.declaration_amount = int(eval(line.compute_code, {"__builtins__": {}}, code_vars))
except Exception as e:
raise ValidationError(f"Error in compute_code for {line.name}: {e}")
else:
# Allow manual entry
pass
@api.onchange('investment_type_line_id', 'declaration_amount')
def _onchange_declaration_amount_live(self):
for rec in self:
line = rec.investment_type_line_id
if not line or not rec.it_declaration_id:
return
siblings = rec.it_declaration_id.past_employment_costings | rec.it_declaration_id.past_employment_costings_new
code_vars = {}
for sibling in siblings:
code = sibling.investment_type_line_id.investment_code
if code:
code_vars[code] = sibling.declaration_amount or 0
if line.compute_method and line.compute_code:
try:
rec.declaration_amount = int(eval(line.compute_code, {"__builtins__": {}}, code_vars))
except Exception as e:
rec.declaration_amount = 0 # fallback
class us80cCostingType(models.Model):
_name = 'us80c.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('us80c.investment.type')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
declaration_amount = fields.Integer(string='Declaration Amount')
action_id = fields.Many2one('ir.actions.act_window', related='investment_type_line_id.action_id')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
def open_action_wizard(self):
self.ensure_one()
model = self.env[self.action_id.res_model]
action_model = model.sudo().search([('it_declaration_id','=',self.it_declaration_id.id),('us80c_id','=',self.id)],order='id desc',limit=1)
# it_declaration_id
if not action_model:
# Explicitly create record so children get added in create()
action_model = model.sudo().create({
'it_declaration_id': self.it_declaration_id.id,
'us80c_id': self.id,
})
return {
'type': 'ir.actions.act_window',
'name': self.action_id.name,
'res_model': self.action_id.res_model,
'res_id': action_model.id,
'view_mode': self.action_id.view_mode,
'target': 'new',
}
class us80dCostingType(models.Model):
_name = 'us80d.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('us80d.investment.type')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class us10CostingType(models.Model):
_name = 'us10.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('us10.investment.type')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class us80gCostingType(models.Model):
_name = 'us80g.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('us80g.investment.type')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class chapterViaCostingType(models.Model):
_name = 'chapter.via.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('chapter.via.investment.type')
investment_type_id = fields.Many2one('it.investment.type',related='investment_type_line_id.investment_type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class us17CostingType(models.Model):
_name = 'us17.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('us17.investment.type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class OtherILCostingType(models.Model):
_name = 'other.il.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('other.il.investment.type')
declaration_amount = fields.Integer(string='Declaration Amount')
action_id = fields.Many2one('ir.actions.act_window', related='investment_type_line_id.action_id')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
def open_action_wizard(self):
self.ensure_one()
model = self.env[self.action_id.res_model]
action_model = model.sudo().search([('it_declaration_id','=',self.it_declaration_id.id),('other_il_id','=',self.id)],order='id desc',limit=1)
# it_declaration_id
if not action_model:
# Explicitly create record so children get added in create()
action_model = model.sudo().create({
'it_declaration_id': self.it_declaration_id.id,
'other_il_id': self.id,
})
return {
'type': 'ir.actions.act_window',
'name': self.action_id.name,
'res_model': self.action_id.res_model,
'res_id': action_model.id,
'view_mode': self.action_id.view_mode,
'target': 'new',
}
class OtherDeclarationCostingType(models.Model):
_name = 'other.declaration.costing.type'
_rec_name = 'investment_type_line_id'
costing_type = fields.Many2one('investment.costings')
it_declaration_id = fields.Many2one('emp.it.declaration')
investment_type_line_id = fields.Many2one('other.declaration.investment.type')
declaration_amount = fields.Integer(string='Declaration Amount')
proof_amount = fields.Integer(string="Proof Amount")
remarks = fields.Text(string="Remarks")
proof = fields.Binary(string="PROOF")
proof_name = fields.Char()
limit = fields.Integer()
class HouseRentDeclaration(models.Model):
_name = 'house.rent.declaration'
_description = 'House Rent Declaration'
it_declaration_id = fields.Many2one('emp.it.declaration')
costing_type = fields.Many2one('investment.costings')
hra_exemption_type = fields.Selection([
('u_s_10', 'U/S 10 - HRA Exemption'),
('u_s_80gg', 'U/S 80GG - HRA Exemption')
], string="HRA Exemption Type", required=True, default='u_s_10')
rent_amount = fields.Float(string="Total Rent for the Period", required=True)
from_date = fields.Date(string="From Date", required=True)
to_date = fields.Date(string="To Date", required=True)
remarks = fields.Text(string="Remarks")
landlord_pan_no = fields.Char(string="Landlord PAN No")
landlord_name_address = fields.Text(string="Landlord Name & Address")
landlord_pan_status = fields.Selection([
('has_pan', 'Landlord has PAN CARD'),
('declaration', 'Declaration By Landlord')
], string="Landlord PAN Status", required=True, default='has_pan')
attachment = fields.Binary(string="Proof Attachment")
attachment_filename = fields.Char(string="Attachment Filename")
@api.model
def create(self, vals):
# Auto-link applicant_id if context is passed correctly
if self.env.context.get('default_it_declaration_id'):
import pdb
pdb.set_trace()
costing_id = self.env['investment.costings'].sudo().search([('id','=',self.env.context.get('it_declaration_id')),('investment_type_id.investment_type','=','house_rent')],limit=1)
vals['costing_type'] = costing_id.id
return super().create(vals)

View File

@ -0,0 +1,220 @@
from odoo import models, fields
class ItInvestmentType(models.Model):
_name = 'it.investment.type'
_rec_name = 'investment_type'
sequence = fields.Integer()
investment_type = fields.Selection(
[('past_employment', 'PAST EMPLOYMENT'), ('us_80c', 'US 80C'), ('us_80d', 'US 80D'), ('us_10', 'US 10'),
('us_80g', 'US 80G'), ('chapter_via', 'CHAPTER VIA'), ('us_17', 'US 17'), ('house_rent', 'HOUSE RENT'),
('other_i_or_l', 'OTHER INCOME/LOSS'), ('other_declaration', 'OTHER DECLARATION')], string="Investment Type",
required=True)
active = fields.Boolean(default=True)
past_employment_ids = fields.One2many('past_employment.investment.type','investment_type')
us80c_ids = fields.One2many('us80c.investment.type', 'investment_type')
us80d_ids = fields.One2many('us80d.investment.type', 'investment_type')
us10_ids = fields.One2many('us10.investment.type', 'investment_type')
us80g_ids = fields.One2many('us80g.investment.type', 'investment_type')
chapter_via_ids = fields.One2many('chapter.via.investment.type', 'investment_type')
us17_ids = fields.One2many('us17.investment.type', 'investment_type')
other_il_ids = fields.One2many('other.il.investment.type', 'investment_type')
other_declaration_ids = fields.One2many('other.declaration.investment.type', 'investment_type')
class pastEmpInvestmentType(models.Model):
_name = 'past_employment.investment.type'
_rec_name = 'name'
_sql_constraints = [
('investment_code_unique', 'unique(investment_code)', 'Code must be unique'),
]
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
investment_code = fields.Char()
compute_method = fields.Boolean()
compute_code = fields.Text('Python Code')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class us80cInvestmentType(models.Model):
_name = 'us80c.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
investment_code = fields.Char()
compute_method = fields.Boolean()
compute_code = fields.Text('Python Code')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
require_action = fields.Boolean()
action_id = fields.Many2one('ir.actions.act_window')
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class us80dInvestmentType(models.Model):
_name = 'us80d.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
for_family = fields.Boolean()
for_parents = fields.Boolean()
for_senior_parent = fields.Boolean()
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class us10InvestmentType(models.Model):
_name = 'us10.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class us80gInvestmentType(models.Model):
_name = 'us80g.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", required=True)
class chapterViaInvestmentType(models.Model):
_name = 'chapter.via.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class us17InvestmentType(models.Model):
_name = 'us17.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class OtherILInvestmentType(models.Model):
_name = 'other.il.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
require_action = fields.Boolean()
action_id = fields.Many2one('ir.actions.act_window')
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
class OtherDeclarationInvestmentType(models.Model):
_name = 'other.declaration.investment.type'
_rec_name = 'name'
name = fields.Char(string='GENERAL', required=True)
investment_type = fields.Many2one('it.investment.type')
limit = fields.Integer(string='LIMIT')
sequence = fields.Integer()
active = fields.Boolean(default=True)
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime'),
('both', 'Both')
], string="Tax Regime", store=True, required=True)
#
# class ItInvestmentTypeLine(models.Model):
# _name = 'it.investment.type.line'
# _description = 'IT Investment Type Line'
# _rec_name = 'name'
#
# investment_type_id = fields.Many2one(
# 'it.investment.type',
# string="Investment Type",
# required=True,
# ondelete='cascade'
# )
# investment_type = fields.Selection(
# [('past_employment', 'PAST EMPLOYMENT'), ('us_80c', 'US 80C'), ('us_80d', 'US 80D'), ('us_10', 'US 10'),
# ('us_80g', 'US 80G'), ('chapter_via', 'CHAPTER VIA'), ('us_17', 'US 17'), ('house_rent', 'HOUSE RENT'),
# ('other_i_or_l', 'OTHER INCOME/LOSS'), ('other_declaration', 'OTHER DECLARATION')], string="Investment Type",
# related='investment_type_id.name')
# name = fields.Char(string="Line Name", required=True)
# need_action = fields.Boolean(string="Needs Action")
# action_id = fields.Many2one(
# 'ir.actions.actions',
# string="Action",
# help="Linked Odoo action if needed"
# )
# tax_regime = fields.Selection([
# ('new', 'New Regime'),
# ('old', 'Old Regime')
# ], string="Tax Regime", required=True)
# sequence = fields.Integer()
# active = fields.Boolean(default=True)
# limit = fields.Integer()

View File

@ -0,0 +1,20 @@
from odoo import models, fields, api, _
class ITTaxStatement(models.Model):
_name = 'it.tax.statement'
_description = 'IT Tax Statement'
_rec_name = 'employee_id'
employee_id = fields.Many2one('hr.employee', required=True)
declaration_id = fields.Many2one('emp.it.declaration', required=True)
period_id = fields.Many2one('payroll.period', related='declaration_id.period_id', store=True)
period_line = fields.Many2one('payroll.period.line')
total_declared_amount = fields.Float(compute='_compute_totals')
tax_regime = fields.Selection(related='declaration_id.tax_regime')
pdf_generated = fields.Boolean(default=False)
@api.depends('declaration_id')
def _compute_totals(self):
for rec in self:
rec.total_declared_amount = sum(rec.declaration_id.investment_costing_ids.mapped('amount'))

View File

@ -0,0 +1,594 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
import math
class ITTaxStatementWizard(models.TransientModel):
_name = 'it.tax.statement.wizard'
_rec_name = 'employee_id'
_description = 'Generate IT Tax Statement (Old vs New)'
# Inputs
employee_id = fields.Many2one('hr.employee', required=True, default=lambda self: self.env.user.employee_id.id)
emp_doj = fields.Date(related='employee_id.doj', store=True)
contract_id = fields.Many2one('hr.contract', related='employee_id.contract_id', required=True)
period_id = fields.Many2one('payroll.period', required=True)
period_line = fields.Many2one('payroll.period.line')
# Taxpayer profile
taxpayer_name = fields.Char(related='employee_id.name')
taxpayer_age = fields.Integer(required=True, default=False)
residential_status = fields.Selection([
('RESIDENT', 'Resident'),
('NON-RESIDENT', 'Non-Resident')
], default='RESIDENT', required=True)
parent_age = fields.Integer(default=65)
# Tax regime selection
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime')
], string="Tax Regime", required=True, default='new')
lock_regime = fields.Selection([
('UNLOCKED', 'Unlocked'),
('LOCKED', 'Locked')
], default='UNLOCKED', string="Lock Regime")
# Computed fields for salary breakdown
basic_salary = fields.Float(compute='_compute_salary_components', store=False)
hra_salary = fields.Float(compute='_compute_salary_components', store=False)
lta_salary = fields.Float(compute='_compute_salary_components', store=False)
special_allowance = fields.Float(compute='_compute_salary_components', store=False)
gross_salary = fields.Float(compute='_compute_salary_components', store=False)
# Deductions
professional_tax = fields.Float(compute='_compute_deductions', store=False)
standard_deduction = fields.Float(compute='_compute_deductions', store=False)
nps_employer_contribution = fields.Float(compute='_compute_deductions', store=False)
# Other income
other_income = fields.Float(string="Other Income", default=0.0)
# Additional fields for tax calculation
hra_exemption = fields.Float(string="HRA Exemption", default=0.0)
interest_home_loan_self = fields.Float(string="Interest on Home Loan (Self Occupied)", default=0.0)
interest_home_loan_letout = fields.Float(string="Interest on Home Loan (Let Out)", default=0.0)
rental_income = fields.Float(string="Rental Income", default=0.0)
# Deductions under Chapter VI-A
ded_80C = fields.Float(string="Deduction under 80C", default=0.0)
ded_80CCD1B = fields.Float(string="Deduction under 80CCD(1B)", default=0.0)
ded_80D_self = fields.Float(string="Deduction under 80D (Self)", default=0.0)
ded_80D_parents = fields.Float(string="Deduction under 80D (Parents)", default=0.0)
ded_80G = fields.Float(string="Deduction under 80G", default=0.0)
ded_other = fields.Float(string="Other Deductions", default=0.0)
def _get_applicable_slab(self, regime, age, residence_type):
"""Get the applicable tax slab based on regime, age, and residence type"""
# Determine age category
if age < 60:
age_category = 'below_60'
elif age < 80:
age_category = '60_to_80'
else:
age_category = 'above_80'
# Search for slab master
slab_master = self.env['it.slab.master'].search([
('regime', '=', regime),
('age_category', '=', age_category),
'|',
('residence_type', '=', residence_type.lower()),
('residence_type', '=', 'both')
], limit=1)
if not slab_master:
raise ValidationError(_(
"No tax slab found for %s Regime with Age Category: %s and Residence Type: %s"
) % (regime.capitalize(), age_category.replace('_', ' ').title(), residence_type))
return slab_master
def _compute_tax_using_slab(self, taxable, slab_master):
"""Compute tax using slab master rules"""
tax = 0.0
# Get rules sorted by min_income
rules = slab_master.rules.sorted('min_income')
for rule in rules:
if taxable <= rule.min_income:
continue
# Calculate amount in this bracket
bracket_max = rule.max_income if rule.max_income else float('inf')
amount_in_bracket = min(taxable, bracket_max) - rule.min_income
# Apply tax calculation based on rule structure
if rule.fixed_amount and rule.excess_threshold:
# Rule with fixed amount and excess threshold
excess_amount = max(0, taxable - rule.excess_threshold)
tax_for_bracket = rule.fixed_amount + (excess_amount * rule.tax_rate / 100)
else:
# Standard bracket calculation
tax_for_bracket = amount_in_bracket * rule.tax_rate / 100
tax += tax_for_bracket
return tax
@api.depends('employee_id', 'contract_id', 'period_id')
def _compute_salary_components(self):
"""Compute salary components from payroll data"""
for rec in self:
if not rec.employee_id or not rec.contract_id:
continue
# Get payslip for the period
payslip = self.env['hr.payslip'].search([
('employee_id', '=', rec.employee_id.id),
('date_from', '>=', rec.period_line.from_date),
('date_to', '<=', rec.period_line.to_date),
('state', 'in', ['verify','done','paid'])
], limit=1)
if payslip:
# Extract salary components from payslip lines
rec.basic_salary = self._get_salary_rule_amount(payslip, 'BASIC')
rec.hra_salary = self._get_salary_rule_amount(payslip, 'HRA')
rec.lta_salary = self._get_salary_rule_amount(payslip, 'LTA')
rec.special_allowance = self._get_salary_rule_amount(payslip, 'SPA')
rec.gross_salary = self._get_salary_rule_amount(payslip, 'GROSS')
else:
# Fallback to contract values
rec.basic_salary = rec.contract_id.wage * 0.4 # Assuming 40% basic
rec.hra_salary = rec.contract_id.wage * 0.2 # Assuming 20% HRA
rec.lta_salary = rec.contract_id.wage * 0.1 # Assuming 10% LTA
rec.special_allowance = rec.contract_id.wage * 0.3 # Remaining as special allowance
rec.gross_salary = rec.contract_id.wage
def fetch_salary_components(self):
"""fetch salary components from payroll data"""
for rec in self:
if not rec.employee_id or not rec.contract_id:
continue
data = {
'basic_salary' : {'actual':[],'projected':[]},
'hra_salary': {'actual': [], 'projected': []},
'lta_salary': {'actual': [], 'projected': []},
'special_allowance' : {'actual':[],'projected':[]},
'gross_salary' : {'actual':[],'projected':[]}
}
period_lines = rec.period_id.period_line_ids
for line in period_lines:
basic_salary = float()
hra_salary = float()
lta_salary = float()
special_allowance = float()
gross_salary = float()
payslip = self.env['hr.payslip'].search([
('employee_id', '=', rec.employee_id.id),
('date_from', '>=', line.from_date),
('date_to', '<=', line.to_date),
('state', 'in', ['verify', 'done', 'paid'])
], limit=1)
if payslip:
# Extract salary components from payslip lines
basic_salary = self._get_salary_rule_amount(payslip, 'BASIC')
hra_salary = self._get_salary_rule_amount(payslip, 'HRA')
lta_salary = self._get_salary_rule_amount(payslip, 'LTA')
special_allowance = self._get_salary_rule_amount(payslip, 'SPA')
gross_salary = self._get_salary_rule_amount(payslip, 'GROSS')
else:
payslip = self.env['hr.payslip'].sudo().create({
'name': 'Test Payslip',
'employee_id': rec.employee_id.id,
'date_from': line.from_date,
'date_to': line.to_date
})
payslip.sudo().compute_sheet()
# Extract salary components from payslip lines
basic_salary = self._get_salary_rule_amount(payslip, 'BASIC')
hra_salary = self._get_salary_rule_amount(payslip, 'HRA')
lta_salary = self._get_salary_rule_amount(payslip, 'LTA')
special_allowance = self._get_salary_rule_amount(payslip, 'SPA')
gross_salary = self._get_salary_rule_amount(payslip, 'GROSS')
payslip.sudo().action_payslip_cancel()
payslip.sudo().unlink()
if line.from_date <= rec.period_line.from_date:
data['basic_salary']['actual'].append(basic_salary)
data['hra_salary']['actual'].append(hra_salary)
data['lta_salary']['actual'].append(lta_salary)
data['special_allowance']['actual'].append(special_allowance)
data['gross_salary']['actual'].append(gross_salary)
else:
data['basic_salary']['projected'].append(basic_salary)
data['hra_salary']['projected'].append(hra_salary)
data['lta_salary']['projected'].append(lta_salary)
data['special_allowance']['projected'].append(special_allowance)
data['gross_salary']['projected'].append(gross_salary)
return data
def _get_salary_rule_amount(self, payslip, rule_code):
"""Get amount for a specific salary rule from payslip"""
line = payslip.line_ids.filtered(lambda l: l.salary_rule_id.code == rule_code)
return line.total if line else 0.0
@api.depends('employee_id', 'contract_id', 'period_id', 'tax_regime')
def _compute_deductions(self):
"""Compute deductions from payroll data"""
for rec in self:
if not rec.employee_id or not rec.contract_id:
continue
# Get payslip for the period
payslip = self.env['hr.payslip'].search([
('employee_id', '=', rec.employee_id.id),
('date_from', '>=', rec.period_id.from_date),
('date_to', '<=', rec.period_id.to_date),
('state', 'in', ['verify', 'done', 'paid'])
], limit=1)
fy_start = self.period_id.from_date
fy_end = self.period_id.to_date
total_months = ((fy_end.year - fy_start.year) * 12 +
(fy_end.month - fy_start.month) + 1)
line_start = self.period_line.from_date
current_month_index = ((line_start.year - fy_start.year) * 12 +
(line_start.month - fy_start.month) + 1)
if payslip:
rec.professional_tax = (self._get_salary_rule_amount(payslip, 'PT'))*current_month_index
rec.nps_employer_contribution = self._get_salary_rule_amount(payslip, 'PFE')
else:
rec.professional_tax = 0.0
rec.nps_employer_contribution = 0.0
# Get standard deduction from slab master
if rec.tax_regime == 'new':
slab_master = self._get_applicable_slab('new', rec.taxpayer_age, rec.residential_status)
else:
slab_master = self._get_applicable_slab('old', rec.taxpayer_age, rec.residential_status)
rec.standard_deduction = slab_master.standard_deduction if slab_master else (
75000 if rec.tax_regime == 'new' else 50000
)
@api.onchange('employee_id')
def onchange_employee_id(self):
for rec in self:
if rec.employee_id and rec.employee_id.birthday:
age = relativedelta(date.today(), rec.employee_id.birthday).years
rec.taxpayer_age = age
else:
rec.taxpayer_age = rec.taxpayer_age or 0
@api.onchange('basic_salary', 'hra_salary')
def onchange_hra_exemption(self):
"""Calculate HRA exemption based on salary components"""
for rec in self:
if rec.basic_salary and rec.hra_salary:
# Basic formula for HRA exemption
# Minimum of:
# 1. Actual HRA received
# 2. 50% of basic salary (for metro cities) or 40% (non-metro)
# 3. Rent paid minus 10% of basic salary
# Assuming metro city for calculation
exemption_option1 = rec.hra_salary
exemption_option2 = 0.5 * rec.basic_salary
# Rent paid would need to be input by user
rent_paid = rec.hra_exemption or 0
exemption_option3 = max(0, rent_paid - 0.1 * rec.basic_salary)
rec.hra_exemption = min(exemption_option1, exemption_option2, exemption_option3)
# --- Tax Calculation Methods ---
def _old_basic_exemption(self, age):
if age < 60:
return 250000.0
elif age < 80:
return 300000.0
return 500000.0
def _rebate_old(self, taxable, slab_tax):
if self.residential_status != 'RESIDENT':
return 0.0
if taxable <= 500000.0:
return min(12500.0, slab_tax)
return 0.0
def _rebate_new(self, taxable, slab_tax):
if self.residential_status != 'RESIDENT':
return 0.0
if taxable >= 1200000.0:
needed = taxable - 1200000.0
if slab_tax >= needed:
return max(0.0, slab_tax - needed)
return 0.0
else:
return min(60000.0, slab_tax)
def _apply_surcharge_with_mr(self, slab_master, taxable, tax_after_rebate, regime):
rules = slab_master.rules.sorted('min_income')
table = [(rule.min_income, rule.surcharge_rate) for rule in rules if rule.surcharge_rate > 0]
threshold = None
rate = 0.0
for th, rt in table:
if taxable > th:
threshold, rate = th, rt
if not threshold:
return 0.0, 0.0, tax_after_rebate
surcharge = tax_after_rebate * rate
total_before_mr = tax_after_rebate + surcharge
mr = max(0.0, total_before_mr)
tax_with_surcharge = total_before_mr - mr
return surcharge, mr, tax_with_surcharge
def _compute_tax_old_regime(self, taxable):
# Get applicable slab
slab_master = self._get_applicable_slab('old', self.taxpayer_age, self.residential_status)
# Compute slab tax
slab_tax = self._compute_tax_using_slab(taxable, slab_master)
# Apply rebate
rebate = self._rebate_old(taxable, slab_tax)
tax_after_rebate = max(0.0, slab_tax - rebate)
# Apply surcharge and marginal relief
surcharge, marginal_relief, tax_with_surcharge = self._apply_surcharge_with_mr(
slab_master, taxable, tax_after_rebate, regime='old'
)
# Apply cess
rules = slab_master.rules.sorted('min_income')
cess_rate = [rule.cess_rate for rule in rules if rule.min_income<=taxable and rule.max_income >= taxable]
cess = tax_with_surcharge * cess_rate[0]/100
total_tax = tax_with_surcharge + cess
return {
'taxable_income': taxable,
'slab_tax': slab_tax,
'rebate_87a': rebate,
'tax_after_rebate': tax_after_rebate,
'surcharge': surcharge,
'marginal_relief': marginal_relief,
'tax_with_surcharge': tax_with_surcharge,
'cess_4pct': cess,
'total_tax': total_tax
}
def _compute_tax_new_regime(self, taxable):
# Get applicable slab (new regime doesn't depend on age)
slab_master = self._get_applicable_slab('new', self.taxpayer_age, self.residential_status)
# Compute slab tax
slab_tax = self._compute_tax_using_slab(taxable, slab_master)
# Apply rebate
rebate = self._rebate_new(taxable, slab_tax)
tax_after_rebate = max(0.0, slab_tax - rebate)
# Apply surcharge and marginal relief
surcharge, marginal_relief, tax_with_surcharge = self._apply_surcharge_with_mr(
slab_master, taxable, tax_after_rebate, regime='new'
)
rules = slab_master.rules.sorted('min_income')
cess_rate = [rule.cess_rate for rule in rules if rule.min_income<=taxable and rule.max_income >= taxable]
# Apply cess
cess = tax_with_surcharge * cess_rate[0]/100
total_tax = tax_with_surcharge + cess
return {
'taxable_income': taxable,
'slab_tax': slab_tax,
'rebate_87a': rebate,
'tax_after_rebate': tax_after_rebate,
'surcharge': surcharge,
'marginal_relief': marginal_relief,
'tax_with_surcharge': tax_with_surcharge,
'cess_4pct': cess,
'total_tax': total_tax
}
def _compute_house_property_income(self):
"""Returns net house property income"""
rent = float(self.rental_income or 0.0)
if rent > 0.0:
nav = rent
std_ded = 0.30 * nav
interest_allowed = float(self.interest_home_loan_letout or 0.0)
hp_income = nav - std_ded - interest_allowed
else:
interest_allowed = min(float(self.interest_home_loan_self or 0.0), 200000.0)
hp_income = -interest_allowed
return hp_income
def _prepare_income_tax_data(self):
"""Prepare data for the tax statement report"""
today = date.today()
fy_start = self.period_id.from_date
fy_end = self.period_id.to_date
total_months = ((fy_end.year - fy_start.year) * 12 +
(fy_end.month - fy_start.month) + 1)
line_start = self.period_line.from_date
current_month_index = ((line_start.year - fy_start.year) * 12 +
(line_start.month - fy_start.month) + 1)
if today.month >= 4:
fy_start = date(today.year, 4, 1)
fy_end = date(today.year + 1, 3, 31)
else:
fy_start = date(today.year - 1, 4, 1)
fy_end = date(today.year, 3, 31)
# Calculate taxable income for both regimes
# Old regime
old_deductions = (
self.standard_deduction +
self.hra_exemption +
self.professional_tax +
self.ded_80C +
self.ded_80CCD1B +
self.ded_80D_self +
self.ded_80D_parents +
self.ded_80G +
self.ded_other +
self.nps_employer_contribution
)
# House property income
hp_income = self._compute_house_property_income()
# Taxable income for old regime
taxable_old = max(0.0, (self.gross_salary * total_months) + self.other_income + hp_income - self.standard_deduction)
# New regime - fewer deductions
new_deductions = (
self.standard_deduction +
self.professional_tax +
self.nps_employer_contribution
)
# Taxable income for new regime
taxable_new = max(0.0, (self.gross_salary * total_months) + self.other_income + hp_income - self.standard_deduction)
# Compute tax for both regimes
tax_result_old = self._compute_tax_old_regime(taxable_old)
tax_result_new = self._compute_tax_new_regime(taxable_new)
# Determine which regime to use
if self.tax_regime == 'old':
tax_result = tax_result_old
taxable_income = taxable_old
chosen = 'old'
else:
tax_result = tax_result_new
taxable_income = taxable_new
chosen = 'new'
# Calculate tax savings
tax_savings = abs(tax_result_old['total_tax'] - tax_result_new['total_tax'])
beneficial_regime = 'old' if tax_result_old['total_tax'] < tax_result_new['total_tax'] else 'new'
# Prepare data structure matching screenshot format
# Financial year (period_id)
fy_start = self.period_id.from_date
fy_end = self.period_id.to_date
total_months = ((fy_end.year - fy_start.year) * 12 +
(fy_end.month - fy_start.month) + 1)
# Current month (period_line)
line_start = self.period_line.from_date
current_month_index = ((line_start.year - fy_start.year) * 12 +
(line_start.month - fy_start.month) + 1)
tax_result['roundoff_taxable_income'] = float(round(tax_result["taxable_income"] / 10) * 10)
birthday = self.employee_id.birthday
if birthday:
diff = relativedelta(date.today(), birthday)
years_months = f"{diff.years} years {diff.months} months"
else:
years_months = "N/A"
month_age = str(self.period_line.name)+ " / " + str(years_months)
salary_components_data = self.fetch_salary_components()
data = {
'financial_year': f"{fy_start.year}-{fy_end.year}",
'assessment_year': fy_end.year + 1,
'report_time': today.strftime('%d-%m-%Y %H:%M'),
'user': 'ESS',
'emp_code': self.employee_id.employee_id,
'company_name': self.employee_id.company_id.name,
'profile': {
'name': self.taxpayer_name or (self.employee_id.name if self.employee_id else ''),
'age': self.taxpayer_age,
'residential_status': self.residential_status,
'parent_age': self.parent_age,
'doj': self.employee_id.doj,
'pan': self.employee_id.pan_no if hasattr(self.employee_id, 'pan_no') else '',
'gender': self.employee_id.gender,
'month_age': month_age
},
'regime_info': {
'lock_regime': self.lock_regime,
'tax_regime': 'NEW REGIME' if self.tax_regime == 'new' else 'OLD REGIME',
},
'salary_components': {
'basic': {'actual': sum(salary_components_data['basic_salary']['actual']), 'projected': sum(salary_components_data['basic_salary']['projected']), 'total':sum(salary_components_data['basic_salary']['actual']) + sum(salary_components_data['basic_salary']['projected'])},
'house_rent': {'actual': sum(salary_components_data['hra_salary']['actual']), 'projected': sum(salary_components_data['hra_salary']['projected']), 'total':sum(salary_components_data['hra_salary']['actual']) + sum(salary_components_data['hra_salary']['projected'])},
'lta': {'actual': sum(salary_components_data['lta_salary']['actual']), 'projected': sum(salary_components_data['lta_salary']['projected']), 'total':sum(salary_components_data['lta_salary']['actual']) + sum(salary_components_data['lta_salary']['projected'])},
'special_allowance':{'actual': sum(salary_components_data['special_allowance']['actual']), 'projected': sum(salary_components_data['special_allowance']['projected']), 'total':sum(salary_components_data['special_allowance']['actual']) + sum(salary_components_data['special_allowance']['projected'])},
'perquisites': {'actual': 0 * current_month_index, 'projected': 0 * (total_months - current_month_index), 'total': 0 * total_months},
'reimbursement': {'actual': 0 * current_month_index, 'projected': 0 * (total_months - current_month_index), 'total': 0 * total_months},
'gross_salary': {'actual': sum(salary_components_data['gross_salary']['actual']), 'projected': sum(salary_components_data['gross_salary']['projected']), 'total':sum(salary_components_data['gross_salary']['actual']) + sum(salary_components_data['gross_salary']['projected'])},
'net_salary': {'actual': self.gross_salary * current_month_index, 'projected': self.gross_salary * (total_months - current_month_index),
'total': self.gross_salary * total_months}
},
'deductions': {
'professional_tax': self.professional_tax,
'standard_deduction': self.standard_deduction,
'nps_employer': self.nps_employer_contribution,
'hra_exemption': self.hra_exemption,
'interest_home_loan': self.interest_home_loan_self + self.interest_home_loan_letout,
'ded_80C': self.ded_80C,
'ded_80CCD1B': self.ded_80CCD1B,
'ded_80D_self': self.ded_80D_self,
'ded_80D_parents': self.ded_80D_parents,
'ded_80G': self.ded_80G,
'ded_other': self.ded_other,
'total_deductions': old_deductions if self.tax_regime == 'old' else new_deductions,
},
'income_details': {
'gross_salary': self.gross_salary,
'other_income': self.other_income,
'house_property_income': hp_income,
'gross_total_income': (self.gross_salary * total_months) + self.other_income + hp_income - self.standard_deduction,
},
'taxable_income': {
'old_regime': taxable_old,
'new_regime': taxable_new,
'current_regime': taxable_income,
},
'tax_computation': tax_result,
'regime_used': chosen,
'comparison': {
'old_regime_tax': tax_result_old['total_tax'],
'new_regime_tax': tax_result_new['total_tax'],
'tax_savings': tax_savings,
'beneficial_regime': beneficial_regime,
}
}
return {'data': data}
def action_generate_report(self):
report_data = self._prepare_income_tax_data()
return self.env.ref('employee_it_declaration.income_tax_statement_action_report').report_action(
self,
data={'report_data': report_data},
)

View File

@ -0,0 +1,61 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from datetime import datetime, timedelta
import calendar
class PayrollPeriod(models.Model):
_name = 'payroll.period'
_description = 'Payroll Period'
_rec_name = 'name'
_sql_constraints = [
('unique_name', 'unique(name)', 'The name must be unique.')
]
from_date = fields.Date(string="From Date", required=True)
to_date = fields.Date(string="To Date", required=True)
name = fields.Char(string="Name", required=True)
period_line_ids = fields.One2many('payroll.period.line', 'period_id', string="Monthly Periods")
@api.onchange('from_date', 'to_date')
def onchange_from_to_date(self):
for rec in self:
if rec.from_date and rec.to_date:
rec.name = f"{rec.from_date.year}-{rec.to_date.year}"
def action_generate_month_lines(self):
self.ensure_one()
if not (self.from_date and self.to_date):
raise ValidationError("Please set both From Date and To Date.")
lines = []
current = self.from_date.replace(day=1)
while current <= self.to_date:
end_of_month = current.replace(day=calendar.monthrange(current.year, current.month)[1])
if end_of_month > self.to_date:
end_of_month = self.to_date
lines.append((0, 0, {
'from_date': current,
'to_date': end_of_month,
'name': f"{current.strftime('%b')} - {str(current.year)[-2:]}"
}))
if current.month == 12:
current = current.replace(year=current.year + 1, month=1)
else:
current = current.replace(month=current.month + 1)
self.period_line_ids = lines
class PayrollPeriodLine(models.Model):
_name = 'payroll.period.line'
_description = 'Payroll Period Line'
_rec_name = 'name'
period_id = fields.Many2one('payroll.period', string="Payroll Period", required=True, ondelete='cascade')
from_date = fields.Date(string="From Date")
to_date = fields.Date(string="To Date")
name = fields.Char(string="Name")

View File

@ -0,0 +1,72 @@
from odoo import fields, models, api, _
from odoo.exceptions import ValidationError
class IncomeTaxSlabMaster(models.Model):
_name = 'it.slab.master'
_description = 'Income Tax Slab Master'
_rec_name = 'name'
_sql_constraints = [
(
'unique_slab',
'unique(regime, age_category, residence_type)',
'Slab must be unique for the same Regime, Age Category, and Residence Type!'
)
]
name = fields.Char(string="Slab Name", required=True)
regime = fields.Selection([
('old', 'Old Tax Regime'),
('new', 'New Tax Regime')
], required=True)
age_category = fields.Selection([
('below_60', 'Below 60 Years'),
('60_to_80', '60-80 Years'),
('above_80', 'Above 80 Years')
], required=True)
residence_type = fields.Selection([
('resident', 'Resident'),
('non_resident', 'Non Resident'),
('both', 'Both')
], required=True)
standard_deduction = fields.Float(string="Standard Deduction")
active = fields.Boolean(default=True)
rules = fields.One2many('it.slab.master.rules','slab_id', string="Slab Rules")
class IncomeTaxSlabMasterRules(models.Model):
_name = 'it.slab.master.rules'
_description = 'Income Tax slab rules'
_rec_name = 'slab_id'
_sql_constraints = [
(
'check_min_max_income',
'CHECK (max_income IS NULL OR max_income > min_income)',
'Max Income must be greater than Min Income!'
)
]
min_income = fields.Float(string="Min Income (₹)", required=True)
max_income = fields.Float(string="Max Income (₹)")
tax_rate = fields.Float(string="Tax Rate (%)", required=True)
fixed_amount = fields.Float(string="Fixed Amount (₹)")
excess_threshold = fields.Float(string="Excess Threshold (₹)")
surcharge_rate = fields.Float(string="Surcharge Rate (%)")
cess_rate = fields.Float(string="Health & Education (%)", default=4.0)
slab_id = fields.Many2one('it.slab.master')
@api.constrains('min_income', 'max_income', 'slab_id')
def _check_overlap(self):
"""Ensure no overlapping or duplicate ranges within the same slab"""
for rule in self:
domain = [
('slab_id', '=', rule.slab_id.id),
('id', '!=', rule.id)
]
others = self.search(domain)
for other in others:
if not (rule.max_income and other.min_income >= rule.max_income) and \
not (other.max_income and rule.min_income >= other.max_income):
raise ValidationError(
f"Income ranges overlap with another slab rule: {other.min_income} - {other.max_income}"
)

View File

@ -0,0 +1,726 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="generate_income_tax_statement_rpt">
<t t-call="web.html_container">
<div class="page">
<t t-set="data" t-value="report_data['data']"/>
<t t-set="profile" t-value="data.get('profile')"/>
<t t-set="company_name" t-value="data.get('company_name')"/>
<t t-set="regime_info" t-value="data.get('regime_info')"/>
<t t-set="salary_components" t-value="data.get('salary_components')"/>
<t t-set="deductions" t-value="data.get('deductions')"/>
<t t-set="income_details" t-value="data.get('income_details')"/>
<t t-set="taxable_income" t-value="data.get('taxable_income')"/>
<t t-set="tax_computation" t-value="data.get('tax_computation')"/>
<t t-set="regime_used" t-value="data.get('regime_used')"/>
<t t-set="comparison" t-value="data.get('comparison')"/>
<!-- Set Dynamic Variables -->
<t t-set="emp_code" t-value="data.get('emp_code')"/>
<t t-set="name" t-value="profile.get('name', '')"/>
<t t-set="pan" t-value="profile.get('pan', '')"/>
<t t-set="month_age" t-value="profile.get('month_age', '')"/>
<t t-set="gender" t-value="(profile.get('gender', '') or '').upper()"/>
<t t-set="joining_date" t-value="profile.get('doj', '')"/>
<t t-set="leaving_date" t-value=""/>
<t t-set="status" t-value="Active"/>
<t t-set="lock_regime" t-value="regime_info.get('lock_regime', '')"/>
<t t-set="net_salary"
t-value="'{:,.0f}'.format(salary_components.get('net_salary', {}).get('total', 0))"/>
<t t-set="tax_employment" t-value="'{:,.0f}'.format(deductions.get('professional_tax', 0))"/>
<t t-set="standard_deduction" t-value="'{:,.0f}'.format(deductions.get('standard_deduction', 0))"/>
<t t-set="other_income" t-value="'{:,.0f}'.format(income_details.get('other_income', 0))"/>
<t t-set="gross_total_income" t-value="'{:,.0f}'.format(income_details.get('gross_total_income', 0))"/>
<t t-set="taxable_income" t-value="'{:,.0f}'.format(tax_computation.get('taxable_income', 0))"/>
<t t-set="roundoff_taxable_income" t-value="'{:,.0f}'.format(tax_computation.get('roundoff_taxable_income', 0))"/>
<t t-set="tax_payable" t-value="'{:,.0f}'.format(tax_computation.get('slab_tax', 0))"/>
<t t-set="rebate_87a" t-value="'{:,.0f}'.format(tax_computation.get('rebate_87a', 0))"/>
<t t-set="cess" t-value="'{:,.0f}'.format(tax_computation.get('cess_4pct', 0))"/>
<t t-set="total_tax" t-value="'{:,.0f}'.format(tax_computation.get('total_tax', 0))"/>
<t t-set="report_time" t-value="data.get('report_time', '')"/>
<!-- Header -->
<div style="text-align: center; margin-bottom: 20px;">
<h2 style="font-weight: bold; margin-bottom: 5px;"><t t-esc="company_name"/></h2>
<h3 style="font-weight: bold; margin-top: 0;">INCOME TAX COMPUTATION STATEMENT</h3>
</div>
<!-- Employee Info -->
<table class="table table-sm" style="width: 100%; margin-bottom: 25px;">
<tr>
<td style="width: 33%;">
<strong>Emp Code:</strong>
<t t-esc="emp_code"/>
</td>
<td style="width: 33%;">
<strong>Name:</strong>
<t t-esc="name"/>
</td>
</tr>
</table>
<table class="table table-sm" style="width: 100%; margin-bottom: 25px;">
<tr>
<td>
<strong>Assessment Year:</strong>
<t t-esc="data.get('assessment_year', '')"/>-
<t t-esc="(data.get('assessment_year', 0) or 0) + 1"/>
</td>
<td>
<strong>Month / Age:</strong>
<t t-esc="month_age"/>
</td>
<td style="width: 34%;">
<strong>PAN:</strong>
<t t-esc="pan"/>
</td>
</tr>
<tr>
<td>
<strong>Date of Joining:</strong>
<t t-esc="joining_date"/>
</td>
<td>
<strong>Leaving Date:</strong>
<t t-esc="leaving_date"/>
</td>
<td>
<strong>Gender:</strong>
<t t-esc="gender"/>
</td>
</tr>
</table>
<!-- Head of Income -->
<h4 style="font-weight: bold; border-bottom: 2px solid #ddd; padding-bottom: 5px; margin-bottom: 15px;">
Head of Income
</h4>
<table class="table table-bordered table-sm" style="width: 100%; margin-bottom: 20px;">
<thead>
<tr style="background-color: #f8f9fa;">
<th style="font-weight: bold; text-align: left;">Description</th>
<th style="font-weight: bold; text-align: right;">Actual</th>
<th style="font-weight: bold; text-align: right;">Projected</th>
<th style="font-weight: bold; text-align: right;">Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>Basic</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('basic', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('basic', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('basic', {}).get('total', 0))"/>
</tr>
<tr>
<td>House Rent</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('house_rent', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('house_rent', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('house_rent', {}).get('total', 0))"/>
</tr>
<tr>
<td>LTA</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('lta', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('lta', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('lta', {}).get('total', 0))"/>
</tr>
<tr>
<td>Special Allowance</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('special_allowance', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('special_allowance', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('special_allowance', {}).get('total', 0))"/>
</tr>
<tr>
<td>Reimbursement</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('reimbursement', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('reimbursement', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('reimbursement', {}).get('total', 0))"/>
</tr>
<tr style="border-top: 2px solid #ddd; font-weight: bold;">
<td>Gross Salary</td>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('gross_salary', {}).get('actual', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('gross_salary', {}).get('projected', 0))"/>
<td style="text-align: right;"
t-esc="'{:,.0f}'.format(salary_components.get('gross_salary', {}).get('total', 0))"/>
</tr>
<tr>
<td>Less: Exemption under section 10</td>
<td colspan="3"></td>
</tr>
<tr style="border-top: 2px solid #ddd; font-weight: bold; margin-bottom: 8px; margin-top: 10px;">
<td>Net Salary</td>
<td colspan="2"></td>
<td style="text-align: right;"
t-esc="net_salary"/>
</tr>
<tr style="border-top: 2px solid #ddd; margin-bottom: 8px; margin-top: 10px;">
<td><strong>Less:</strong> Deduction under section 16</td>
<td colspan="3"></td>
</tr>
<tr style="border-top: 2px solid #ddd; margin-bottom: 8px; margin-top: 10px;">
<td style="padding-left: 30px;">Tax on Employment: Sec 16 - Prof. Tax</td>
<td style="text-align: right;"
t-esc="tax_employment"/>
<td colspan="2"></td>
</tr>
<tr style="border-top: 2px solid #ddd; margin-bottom: 8px; margin-top: 10px;">
<td style="padding-left: 30px;">Less: Standard Deduction for Salaried Employees</td>
<td colspan="2"></td>
<td style="text-align: right;"
t-esc="standard_deduction"/>
</tr>
<tr style="border-top: 2px solid #ddd; margin-bottom: 8px; margin-top: 10px;">
<td style="padding-left: 30px;">Total</td>
<td style="text-align: right;"
t-esc="tax_employment"/>
<td colspan="1"></td>
<td style="text-align: right;"
t-esc="standard_deduction"/>
</tr>
<tr style="border-top: 2px solid #ddd; font-weight: bold; margin-bottom: 8px; margin-top: 10px;">
<td>Other Income</td>
<td colspan="3"></td>
</tr>
</tbody>
</table>
<!-- <div style="margin-bottom: 8px;">-->
<!-- <strong>Net Salary:</strong>-->
<!-- <span style="float: right;" t-esc="net_salary"/>-->
<!-- </div>-->
<!-- <div style="margin-bottom: 8px;">-->
<!-- <strong>Other Income:</strong>-->
<!-- <span style="float: right;" t-esc="other_income"/>-->
<!-- </div>-->
<div style="margin-bottom: 20px; font-weight: bold; border-top: 1px solid #ddd; padding-top: 8px;">
<strong>Gross Total Income:</strong>
<span style="float: right;" t-esc="gross_total_income"/>
</div>
<!-- Deductions -->
<h4 style="border-bottom: 2px #ddd; padding-bottom: 5px; margin-bottom: 15px;">
<strong>Less</strong> Deductions under Chapter VIA
<span style="float: right;">0</span>
</h4>
<!-- <table class="table table-bordered table-sm" style="width: 100%; margin-bottom: 20px;">-->
<!-- <thead>-->
<!-- <tr style="background-color: #f8f9fa;">-->
<!-- <th style="font-weight: bold; text-align: left;">Investment</th>-->
<!-- <th style="font-weight: bold; text-align: left;">Section</th>-->
<!-- <th style="font-weight: bold; text-align: right;">Gross</th>-->
<!-- <th style="font-weight: bold; text-align: right;">Qualifying</th>-->
<!-- <th style="font-weight: bold; text-align: right;">Deductible</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>National Pension Scheme (Employer contribution)</td>-->
<!-- <td>80CCD(2)</td>-->
<!-- <td style="text-align: right;" t-esc="'{:,.0f}'.format(deductions.get('nps_employer', 0))"/>-->
<!-- <td style="text-align: right;" t-esc="'{:,.0f}'.format(deductions.get('nps_employer', 0))"/>-->
<!-- <td style="text-align: right;" t-esc="'{:,.0f}'.format(deductions.get('nps_employer', 0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Others</td>-->
<!-- <td>-</td>-->
<!-- <td style="text-align: right;"-->
<!-- t-esc="'{:,.0f}'.format(deductions.get('total_deductions', 0) - deductions.get('nps_employer', 0))"/>-->
<!-- <td style="text-align: right;"-->
<!-- t-esc="'{:,.0f}'.format(deductions.get('total_deductions', 0) - deductions.get('nps_employer', 0))"/>-->
<!-- <td style="text-align: right;"-->
<!-- t-esc="'{:,.0f}'.format(deductions.get('total_deductions', 0) - deductions.get('nps_employer', 0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- Tax Computation -->
<h4 style="font-weight: bold; border-bottom: 2px solid #ddd; padding-bottom: 5px; margin-bottom: 15px;">
Tax Calculation
</h4>
<table class="table table-sm" style="width: 100%; margin-bottom: 20px;">
<tr>
<td style="width: 70%;">
<strong>Taxable Income:</strong>
</td>
<td style="width: 30%; text-align: right;">
<t t-esc="taxable_income"/>
</td>
</tr>
<tr>
<td style="width: 70%;">
Round off to nearest 10 Rupee:
</td>
<td style="width: 30%; text-align: right;">
<t t-esc="roundoff_taxable_income"/>
</td>
</tr>
<tr>
<td>
<strong>Tax Payable on Total Income:</strong>
</td>
<td style="text-align: right;">
<t t-esc="tax_payable"/>
</td>
</tr>
<tr>
<td>
<strong>Less: Rebate u/s 87A (Tax Credit)</strong>
</td>
<td style="text-align: right;">
<t t-esc="rebate_87a"/>
</td>
</tr>
<tr>
<td>
<strong>Add: Surcharge</strong>
</td>
<td style="text-align: right;">
0
</td>
</tr>
<tr>
<td>
<strong>Add: Health and Education Cess:</strong>
</td>
<td style="text-align: right;">
<t t-esc="cess"/>
</td>
</tr>
<tr>
<td>
<strong>Less: Relief under section 89(1)</strong>
</td>
<td style="text-align: right;">
0
</td>
</tr>
<tr>
<td>
<strong>Less: Details of Tax Collected at Source</strong>
</td>
<td style="text-align: right;">
0
</td>
</tr>
<tr style="border-top: 2px solid #ddd; font-weight: bold;">
<td>
<strong>Total Tax Payable:</strong>
</td>
<td style="text-align: right;">
<t t-esc="total_tax"/>
</td>
</tr>
</table>
<!-- Tax Breakdown -->
<h4 style="font-weight: bold; border-bottom: 2px solid #ddd; padding-bottom: 5px; margin-bottom: 15px;">
Tax Deduction Details
</h4>
<table class="table table-bordered table-sm" style="width: 100%; margin-bottom: 20px;">
<thead>
<tr style="background-color: #f8f9fa;">
<th style="font-weight: bold; text-align: left;">Particulars</th>
<th style="font-weight: bold; text-align: right;">Taxable Income</th>
<th style="font-weight: bold; text-align: right;">Income Tax</th>
</tr>
</thead>
<tbody>
<tr>
<td>Total annual income and tax</td>
<td style="text-align: right;" t-esc="taxable_income"/>
<td style="text-align: right;" t-esc="total_tax"/>
</tr>
<tr>
<td>Less: Tax deducted current employer (up to previous month)</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr>
<td>Less: Tax deducted from previous Employer / Self Tax Paid</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr style="font-weight: bold;">
<td>Balance Tax for the year</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;" t-esc="total_tax"/>
</tr>
<tr>
<td>Less: Adhoc tax deducted in Off-Cycle in current month</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr style="font-weight: bold;">
<td><strong>Balance Tax</strong></td>
<td style="text-align: right;">0</td>
<td style="text-align: right;" t-esc="total_tax"/>
</tr>
<tr>
<td><strong>Tax deducted from current month salary</strong></td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr>
<td>Per month Tax (balance / No. of months incl. current month)</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">0</td>
</tr>
<tr style="font-weight: bold; border-top: 2px solid #ddd;">
<td>Adhoc Tax to be deducted from current month salary</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;" t-esc="total_tax"/>
</tr>
<tr style="font-weight: bold; border-top: 2px solid #ddd;">
<td><strong>Total Tax deducted from current month salary + adhoc + off-cycle</strong></td>
<td style="text-align: right;">0</td>
<td style="text-align: right;" t-esc="total_tax"/>
</tr>
</tbody>
</table>
<div style="margin-top: 30px; display: flex; justify-content: space-between;">
<div>
<strong>Report Time:</strong>
<t t-esc="report_time"/>
</div>
<div style="text-align: right;">
<strong>User:</strong>
<t t-esc="data.get('user', '')"/>
</div>
</div>
</div>
</t>
</template>
<!-- <template id="generate_income_tax_statement_rpt">-->
<!-- <t t-call="web.basic_layout">-->
<!-- <main class="page">-->
<!-- <t t-set="data" t-value="report_data['data']"/>-->
<!-- <t t-set="profile" t-value="data.get('profile')"/>-->
<!-- <t t-set="regime_info" t-value="data.get('regime_info')"/>-->
<!-- <t t-set="salary_components" t-value="data.get('salary_components')"/>-->
<!-- <t t-set="deductions" t-value="data.get('deductions')"/>-->
<!-- <t t-set="income_details" t-value="data.get('income_details')"/>-->
<!-- <t t-set="taxable_income" t-value="data.get('taxable_income')"/>-->
<!-- <t t-set="tax_computation" t-value="data.get('tax_computation')"/>-->
<!-- <t t-set="regime_used" t-value="data.get('regime_used')"/>-->
<!-- <t t-set="comparison" t-value="data.get('comparison')"/>-->
<!-- &lt;!&ndash; Report Title &ndash;&gt;-->
<!-- <div class="text-center" style="margin-bottom: 25px;">-->
<!-- <h3 style="font-size:20px; font-weight:bold; text-decoration: underline;">INCOME TAX COMPUTATION STATEMENT</h3>-->
<!-- <p style="font-size:14px; margin-top: 5px;">-->
<!-- Assessment Year:-->
<!-- <t t-esc="data.get('assessment_year')"/>-->
<!-- |-->
<!-- Financial Year:-->
<!-- <t t-esc="data.get('financial_year')"/>-->
<!-- |-->
<!-- <t t-esc="regime_info.get('tax_regime')"/>-->
<!-- </p>-->
<!-- </div>-->
<!-- &lt;!&ndash; Employee Info &ndash;&gt;-->
<!-- <table class="table table-sm" style="margin-bottom: 25px; font-size: 13px;">-->
<!-- <tr>-->
<!-- <td><strong>Employee Name</strong></td>-->
<!-- <td><t t-esc="profile.get('name')"/></td>-->
<!-- <td><strong>PAN</strong></td>-->
<!-- <td><t t-esc="profile.get('pan', '')"/></td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td><strong>Age</strong></td>-->
<!-- <td><t t-esc="profile.get('age')"/></td>-->
<!-- <td><strong>Residential Status</strong></td>-->
<!-- <td><t t-esc="profile.get('residential_status')"/></td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td><strong>Parent's Age</strong></td>-->
<!-- <td><t t-esc="profile.get('parent_age')"/></td>-->
<!-- <td><strong>User</strong></td>-->
<!-- <td><t t-esc="data.get('user')"/></td>-->
<!-- </tr>-->
<!-- </table>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Regime Lock Status</td>-->
<!-- <td>-->
<!-- <t t-esc="regime_info.get('lock_regime')"/>-->
<!-- </td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Current Tax Regime</td>-->
<!-- <td>-->
<!-- <t t-esc="regime_info.get('tax_regime')"/>-->
<!-- </td>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- &lt;!&ndash; Head of Income &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #007bff;">Head of Income</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <thead style="background:#e9ecef;">-->
<!-- <tr>-->
<!-- <th>Particulars</th>-->
<!-- <th class="text-right">Actual</th>-->
<!-- <th class="text-right">Projected</th>-->
<!-- <th class="text-right">Total</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Basic</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('basic', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('basic', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('basic', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>House Rent</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('house_rent', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('house_rent', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('house_rent', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>LTA</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('lta', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('lta', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('lta', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Special Allowance</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('special_allowance', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('special_allowance', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('special_allowance', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Perquisites</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('perquisites', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('perquisites', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('perquisites', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Reimbursement</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('reimbursement', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('reimbursement', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('reimbursement', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Gross Salary</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('gross_salary', {}).get('actual',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('gross_salary', {}).get('projected',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(salary_components.get('gross_salary', {}).get('total',0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- &lt;!&ndash; Deductions &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #007bff;">Deductions</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <thead style="background:#e9ecef;">-->
<!-- <tr>-->
<!-- <th>Particulars</th>-->
<!-- <th class="text-right">Amount (₹)</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Professional Tax</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('professional_tax',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Standard Deduction</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('standard_deduction',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>NPS Employer Contribution</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('nps_employer',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>HRA Exemption</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('hra_exemption',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Interest on Home Loan</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('interest_home_loan',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Deduction under 80C</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_80C',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Deduction under 80CCD(1B)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_80CCD1B',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Deduction under 80D (Self)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_80D_self',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Deduction under 80D (Parents)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_80D_parents',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Deduction under 80G</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_80G',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Other Deductions</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('ded_other',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Total Deductions</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(deductions.get('total_deductions',0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- &lt;!&ndash; Income Details &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #007bff;">Income Details</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <thead style="background:#e9ecef;">-->
<!-- <tr>-->
<!-- <th>Particulars</th>-->
<!-- <th class="text-right">Amount (₹)</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Gross Salary</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(income_details.get('gross_salary',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Other Income</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(income_details.get('other_income',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>House Property Income</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(income_details.get('house_property_income',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Total Income</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(income_details.get('total_income',0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- &lt;!&ndash; Taxable Income &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #007bff;">Taxable Income</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Taxable Income (Old Regime)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(taxable_income.get('old_regime',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Taxable Income (New Regime)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(taxable_income.get('new_regime',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Taxable Income (Current Regime)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(taxable_income.get('current_regime',0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- &lt;!&ndash; Tax Regime Comparison &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #6f42c1;">Tax Regime Comparison</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <thead style="background:#e9ecef;">-->
<!-- <tr>-->
<!-- <th>Particulars</th>-->
<!-- <th class="text-right">Old Regime (₹)</th>-->
<!-- <th class="text-right">New Regime (₹)</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Total Tax Payable</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(comparison.get('old_regime_tax',0))"/>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(comparison.get('new_regime_tax',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Tax Savings</td>-->
<!-- <td class="text-right" colspan="2" t-esc="'{:,.2f}'.format(comparison.get('tax_savings',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Beneficial Regime</td>-->
<!-- <td class="text-center" colspan="2" t-esc="comparison.get('beneficial_regime','').capitalize() + ' Regime'"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- &lt;!&ndash; Tax Computation &ndash;&gt;-->
<!-- <div style="page-break-inside: avoid; margin-bottom:20px;">-->
<!-- <h4 style="background:#f2f2f2; padding:5px; border-left:4px solid #dc3545;">Tax Computation</h4>-->
<!-- <table class="table table-bordered table-sm" style="font-size: 13px;">-->
<!-- <tbody>-->
<!-- <tr>-->
<!-- <td>Taxable Income</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('taxable_income',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Slab Tax</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('slab_tax',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Rebate under Section 87A</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('rebate_87a',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Surcharge</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('surcharge',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Marginal Relief</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('marginal_relief',0))"/>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <td>Health &amp; Education Cess (4%)</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('cess_4pct',0))"/>-->
<!-- </tr>-->
<!-- <tr style="font-weight:bold; background:#f8f9fa;">-->
<!-- <td>Total Tax Payable</td>-->
<!-- <td class="text-right" t-esc="'{:,.2f}'.format(tax_computation.get('total_tax',0))"/>-->
<!-- </tr>-->
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </main>-->
<!-- </t>-->
<!-- </template>-->
</odoo>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<report
id="action_report_it_tax_statement"
model="emp.it.declaration"
string="IT Tax Statement"
report_type="qweb-pdf"
name="your_module_name.report_it_tax_statement"
file="your_module_name.report_it_tax_statement"
print_report_name="'IT_Tax_Statement_%s' % (object.employee_id.name)"
/>
</odoo>

View File

@ -0,0 +1,65 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_payroll_period_user,payroll.period,model_payroll_period,,1,1,1,1
access_payroll_period_line_user,payroll.period.line,model_payroll_period_line,,1,1,1,1
access_it_investment_type,it.investment.type,model_it_investment_type,,1,1,1,1
access_past_employment_investment_type,past_employment.investment.type,model_past_employment_investment_type,,1,1,1,1
access_us80c_investment_type,us80c.investment.type,model_us80c_investment_type,,1,1,1,1
access_us80d_investment_type,us80d.investment.type,model_us80d_investment_type,,1,1,1,1
access_us10_investment_type,us10.investment.type,model_us10_investment_type,,1,1,1,1
access_us80g_investment_type,us80g.investment.type,model_us80g_investment_type,,1,1,1,1
access_chapter_via_investment_type,chapter.via.investment.type,model_chapter_via_investment_type,,1,1,1,1
access_us17_investment_type,us17.investment.type,model_us17_investment_type,,1,1,1,1
access_other_il_investment_type,other.il.investment.type,model_other_il_investment_type,,1,1,1,1
access_other_declaration_investment_type,other.declaration.investment.type,model_other_declaration_investment_type,,1,1,1,1
access_investment_costings,investment.costings,model_investment_costings,,1,1,1,1
access_past_employment_costing_type,past_employment.costing.type,model_past_employment_costing_type,,1,1,1,1
access_us80c_costing_type,us80c.costing.type,model_us80c_costing_type,,1,1,1,1
access_us80d_costing_type,us80d.costing.type,model_us80d_costing_type,,1,1,1,1
access_us10_costing_type,us10.costing.type,model_us10_costing_type,,1,1,1,1
access_us80g_costing_type,us80g.costing.type,model_us80g_costing_type,,1,1,1,1
access_chapter_via_costing_type,chapter.via.costing.type,model_chapter_via_costing_type,,1,1,1,1
access_us17_costing_type,us17.costing.type,model_us17_costing_type,,1,1,1,1
access_other_il_costing_type,other.il.costing.type,model_other_il_costing_type,,1,1,1,1
access_other_declaration_costing_type,other.declaration.costing.type,model_other_declaration_costing_type,,1,1,1,1
access_emp_it_declaration_user,emp.it.declarations,model_emp_it_declaration,base.group_user,1,1,1,1
access_children_education,access.children.education,model_children_education,base.group_user,1,1,1,1
access_children_education_costing,access.children.education.costing,model_children_education_costing,base.group_user,1,1,1,1
access_us80c_insurance_line,access.us80c.insurance.line,model_us80c_insurance_line,,1,1,1,1
access_employee_life_insurance,access.employee.life.insurance,model_employee_life_insurance,,1,1,1,1
access_nsc_declaration_line_user,nsc.declaration.line,model_nsc_declaration_line,base.group_user,1,1,1,1
access_nsc_entry_user,nsc.entry,model_nsc_entry,base.group_user,1,1,1,1
access_self_occupied_property_user,self.occupied.property,model_self_occupied_property,base.group_user,1,1,1,1
access_letout_house_property_user,access.letout.house.property.user,model_letout_house_property,base.group_user,1,1,1,1
access_nsc_interest_line_user,nsc.interest.line,model_nsc_interest_line,base.group_user,1,1,1,1
access_nsc_interest_entry_user,nsc.interest.entry,model_nsc_interest_entry,base.group_user,1,1,1,1
access_house_rent_declaration_user,access.house.rent.declaration.user,model_house_rent_declaration,base.group_user,1,1,1,1
access_it_tax_statement,it.tax.statement,model_it_tax_statement,base.group_user,1,0,0,0
access_it_tax_statement_wizard,it.tax.statement.wizard,model_it_tax_statement_wizard,base.group_user,1,0,0,0
access_it_tax_statement_manager,it.tax.statement,model_it_tax_statement,hr.group_hr_manager,1,1,1,1
access_it_tax_statement_wizard_manager,it.tax.statement.wizard,model_it_tax_statement_wizard,hr.group_hr_manager,1,1,1,1
access_it_slab_master,it.slab.master,model_it_slab_master,base.group_user,1,1,1,1
access_it_slab_master_rules,it.slab.master.rules,model_it_slab_master_rules,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_payroll_period_user payroll.period model_payroll_period 1 1 1 1
3 access_payroll_period_line_user payroll.period.line model_payroll_period_line 1 1 1 1
4 access_it_investment_type it.investment.type model_it_investment_type 1 1 1 1
5 access_past_employment_investment_type past_employment.investment.type model_past_employment_investment_type 1 1 1 1
6 access_us80c_investment_type us80c.investment.type model_us80c_investment_type 1 1 1 1
7 access_us80d_investment_type us80d.investment.type model_us80d_investment_type 1 1 1 1
8 access_us10_investment_type us10.investment.type model_us10_investment_type 1 1 1 1
9 access_us80g_investment_type us80g.investment.type model_us80g_investment_type 1 1 1 1
10 access_chapter_via_investment_type chapter.via.investment.type model_chapter_via_investment_type 1 1 1 1
11 access_us17_investment_type us17.investment.type model_us17_investment_type 1 1 1 1
12 access_other_il_investment_type other.il.investment.type model_other_il_investment_type 1 1 1 1
13 access_other_declaration_investment_type other.declaration.investment.type model_other_declaration_investment_type 1 1 1 1
14 access_investment_costings investment.costings model_investment_costings 1 1 1 1
15 access_past_employment_costing_type past_employment.costing.type model_past_employment_costing_type 1 1 1 1
16 access_us80c_costing_type us80c.costing.type model_us80c_costing_type 1 1 1 1
17 access_us80d_costing_type us80d.costing.type model_us80d_costing_type 1 1 1 1
18 access_us10_costing_type us10.costing.type model_us10_costing_type 1 1 1 1
19 access_us80g_costing_type us80g.costing.type model_us80g_costing_type 1 1 1 1
20 access_chapter_via_costing_type chapter.via.costing.type model_chapter_via_costing_type 1 1 1 1
21 access_us17_costing_type us17.costing.type model_us17_costing_type 1 1 1 1
22 access_other_il_costing_type other.il.costing.type model_other_il_costing_type 1 1 1 1
23 access_other_declaration_costing_type other.declaration.costing.type model_other_declaration_costing_type 1 1 1 1
24 access_emp_it_declaration_user emp.it.declarations model_emp_it_declaration base.group_user 1 1 1 1
25 access_children_education access.children.education model_children_education base.group_user 1 1 1 1
26 access_children_education_costing access.children.education.costing model_children_education_costing base.group_user 1 1 1 1
27 access_us80c_insurance_line access.us80c.insurance.line model_us80c_insurance_line 1 1 1 1
28 access_employee_life_insurance access.employee.life.insurance model_employee_life_insurance 1 1 1 1
29 access_nsc_declaration_line_user nsc.declaration.line model_nsc_declaration_line base.group_user 1 1 1 1
30 access_nsc_entry_user nsc.entry model_nsc_entry base.group_user 1 1 1 1
31 access_self_occupied_property_user self.occupied.property model_self_occupied_property base.group_user 1 1 1 1
32 access_letout_house_property_user access.letout.house.property.user model_letout_house_property base.group_user 1 1 1 1
33 access_nsc_interest_line_user nsc.interest.line model_nsc_interest_line base.group_user 1 1 1 1
34 access_nsc_interest_entry_user nsc.interest.entry model_nsc_interest_entry base.group_user 1 1 1 1
35 access_house_rent_declaration_user access.house.rent.declaration.user model_house_rent_declaration base.group_user 1 1 1 1
36 access_it_tax_statement it.tax.statement model_it_tax_statement base.group_user 1 0 0 0
37 access_it_tax_statement_wizard it.tax.statement.wizard model_it_tax_statement_wizard base.group_user 1 0 0 0
38 access_it_tax_statement_manager it.tax.statement model_it_tax_statement hr.group_hr_manager 1 1 1 1
39 access_it_tax_statement_wizard_manager it.tax.statement.wizard model_it_tax_statement_wizard hr.group_hr_manager 1 1 1 1
40 access_it_slab_master it.slab.master model_it_slab_master base.group_user 1 1 1 1
41 access_it_slab_master_rules it.slab.master.rules model_it_slab_master_rules base.group_user 1 1 1 1

View File

@ -0,0 +1,355 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="emp_it_declaration_list" model="ir.ui.view">
<field name="name">emp.it.declaration.list</field>
<field name="model">emp.it.declaration</field>
<field name="arch" type="xml">
<list>
<field name="period_id"/>
<field name="total_investment"/>
<field name="tax_regime"/>
</list>
</field>
</record>
<record id="view_emp_it_declaration_form" model="ir.ui.view">
<field name="name">emp.it.declarations.form</field>
<field name="model">emp.it.declaration</field>
<field name="arch" type="xml">
<form string="IT Declaration">
<sheet>
<div class="oe_title mb24">
<div class="o_row">
<field name="employee_id" widget="res_partner_many2one" placeholder="Employee Name..." readonly="costing_details_generated"/>
</div>
</div>
<group>
<group>
<field name="period_id" readonly="costing_details_generated"/>
</group>
<group>
<field name="total_investment"/>
<field name="costing_details_generated" invisible="1" force_save="1"/>
<field name="house_rent_costing_id"/>
</group>
</group>
<br/>
<br/>
<field name="tax_regime" nolabel="1" widget="radio" options="{'horizontal': true}"/>
<br/>
<button name="generate_declarations" type="object" class="btn-primary" string="Generate" confirm="Upon Confirming you won't be able to change the Period &amp; Employee" help="Generate Data to upload the declaration Costing" invisible="costing_details_generated"/>
<field name="is_section_open" invisible="1"/> <!-- Store toggle state -->
<group invisible="not costing_details_generated">
<!-- Styled full-width button -->
<div style="background-color: #1167A8; padding: 10px; color: white; font-weight: bold; display: flex; justify-content: space-between; align-items: center; cursor: pointer;">
<span><field name="display_period_label" readonly="1" nolabel="1" style="color: white; font-weight: bold;"/></span>
<button name="toggle_section_visibility"
type="object"
style="background: none; border: none; color: white; font-size: 16px;"
icon="fa-chevron-up"/>
</div>
</group>
<group>
<!-- Collapsible section -->
<div invisible="not is_section_open">
<notebook>
<page string="Total Investment Costing">
<group>
<group>
<field name="investment_costing_ids" nolabel="1">
<list editable="bottom" create="0" delete="0" edit="0">
<field name="investment_type_id"/>
<field name="amount"/>
</list>
</field>
</group>
<group>
</group>
</group>
</page>
</notebook>
</div>
</group>
<notebook invisible="not costing_details_generated">
<!-- <page name="investment_costings" string="Total Investment">-->
<!-- <field name="investment_costing_ids" readonly="1" force_save="1">-->
<!-- <list editable="bottom" create="0" delete="0" edit="0">-->
<!-- <field name="investment_type_id" width="50%"/>-->
<!-- <field name="amount" width="50%" class="text-start"/>-->
<!-- </list>-->
<!-- </field>-->
<!-- </page>-->
<page name="past_employment_costings" string="PAST EMPLOYMENT">
<field name="past_employment_costings" invisible="tax_regime != 'old'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
<field name="past_employment_costings_new" invisible="tax_regime != 'new'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="us_80c_costings" string="US 80C" invisible="tax_regime != 'old'">
<field name="us80c_costings">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="action_id" column_invisible="1"/>
<button name="open_action_wizard"
string="Action"
type="object"
icon="fa-external-link"
invisible="not action_id" width="60px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="200px"/>
<field name="proof" width="100px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="us_80d_costings" string="US 80D" invisible="tax_regime != 'old'">
<group>
<field name="us80d_selection_type" widget="radio" options="{'horizontal': true}" required="tax_regime == 'old' and costing_details_generated"/>
<field name="us80d_health_checkup"/>
</group>
<field name="us80d_costings" invisible="us80d_selection_type != 'self_family'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
<field name="us80d_costings_parents" invisible="us80d_selection_type != 'self_family_parent'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
<field name="us80d_costings_senior_parents" invisible="us80d_selection_type != 'self_family_senior_parent'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="us_10_costing" string="US 10" invisible="tax_regime != 'old'">
<field name="us10_costings">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="us_80g_costing" string="US 80G" invisible="tax_regime != 'old'">
<field name="us80g_costings">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="chapter_via_costings" string="CHAPTER VIA">
<field name="chapter_via_costings" invisible="tax_regime != 'old'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
<field name="chapter_via_costings_new" invisible="tax_regime != 'new'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="us_17_costings" string="US 17" invisible="tax_regime != 'old'">
<field name="us17_costings">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="house_rent_costings" string="HOUSE RENT" invisible="tax_regime != 'old'">
<!-- <field name="house_rent_costing_line_ids"/>-->
<field name="house_rent_costings" context="{
'default_costing_type': house_rent_costing_id
}">
<list string="House Rent Declarations">
<field name="hra_exemption_type"/>
<field name="rent_amount"/>
<field name="from_date"/>
<field name="to_date"/>
<field name="landlord_pan_status"/>
</list>
<form string="House Rent Declaration" class="o_form">
<sheet>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="costing_type" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<group>
<group>
<field name="hra_exemption_type" widget="radio"/>
<field name="landlord_pan_status" widget="radio"/>
</group>
</group>
<notebook>
<page string="Rent Details">
<group col="2">
<field name="rent_amount"/>
<field name="from_date"/>
<field name="to_date"/>
</group>
<field name="remarks" placeholder="Any additional information..."/>
</page>
<page string="Landlord Information">
<group col="2">
<field name="landlord_pan_no" invisible="landlord_pan_status == 'declaration'" required="landlord_pan_status == 'has_pan'"/>
<field name="landlord_name_address"/>
</group>
</page>
<page string="Proof Attachment">
<group>
<field name="attachment" filename="attachment_filename"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</page>
<page name="other_i_or_l_costings" string="OTHER INCOME/LOSS">
<field name="other_il_costings" invisible="tax_regime != 'old'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="action_id" column_invisible="1" force_save="1"/>
<button name="open_action_wizard"
string="Action"
type="object"
icon="fa-external-link"
invisible="not action_id" width="60px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="200px"/>
<field name="proof" width="100px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
<field name="other_il_costings_new" invisible="tax_regime != 'new'">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="action_id" column_invisible="1" force_save="1"/>
<button name="open_action_wizard"
string="Action"
type="object"
icon="fa-external-link"
invisible="not action_id" width="60px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="200px"/>
<field name="proof" width="100px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
<page name="other_declaration_costings" string="Other Declarations" invisible="tax_regime != 'old'">
<field name="other_declaration_costings">
<list editable="bottom" create="0" delete="0">
<field name="investment_type_line_id" width="600px" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="declaration_amount" width="130px"/>
<field name="proof_amount" width="100px" readonly="1" force_save="1"/>
<field name="remarks" width="250px"/>
<field name="proof" width="120px"/>
<field name="limit" readonly="1" force_save="1"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="action_emp_it_declaration" model="ir.actions.act_window">
<field name="name">IT Declarations</field>
<field name="path">income-tax-declaration</field>
<field name="res_model">emp.it.declaration</field>
<field name="view_mode">list,form</field>
</record>
<menuitem id="menu_it_declarations" name="IT Declarations"
parent="hr_payroll.menu_hr_payroll_root"
action="action_emp_it_declaration" sequence="99"/>
</data>
</odoo>

View File

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data>
<record id="view_it_investment_type_list" model="ir.ui.view">
<field name="name">it.investment.type.list</field>
<field name="model">it.investment.type</field>
<field name="arch" type="xml">
<list>
<field name="sequence" widget="handle"/>
<field name="investment_type"/>
<field name="active"/>
</list>
</field>
</record>
<record id="view_it_investment_type_form" model="ir.ui.view">
<field name="name">it.investment.type.form</field>
<field name="model">it.investment.type</field>
<field name="arch" type="xml">
<form string="Investment Type">
<sheet>
<group>
<field name="sequence" invisible="1"/>
<field name="investment_type"/>
<field name="active"/>
</group>
<notebook>
<page string="Past Employment" invisible="investment_type != 'past_employment'">
<field name="past_employment_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="investment_code"/>
<field name="compute_method"/>
<field name="compute_code"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="US 80C" invisible="investment_type != 'us_80c'">
<field name="us80c_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="investment_code"/>
<field name="compute_method"/>
<field name="compute_code"/>
<field name="require_action"/>
<field name="action_id" readonly="not require_action" required="require_action"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="US 80D" invisible="investment_type != 'us_80d'">
<field name="us80d_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="for_family" string="Family"/>
<field name="for_parents" string="Parents"/>
<field name="for_senior_parent" string="Senior Parents"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="US 10" invisible="investment_type != 'us_10'">
<field name="us10_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="US 80G" invisible="investment_type != 'us_80g'">
<field name="us80g_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="Chapter VIA" invisible="investment_type != 'chapter_via'">
<field name="chapter_via_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="US 17" invisible="investment_type != 'us_17'">
<field name="us17_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="Other Income or Loss" invisible="investment_type != 'other_i_or_l'">
<field name="other_il_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="require_action"/>
<field name="action_id" readonly="not require_action" required="require_action"/>
<field name="limit"/>
</list>
</field>
</page>
<page string="Other Declaration" invisible="investment_type != 'other_declaration'">
<field name="other_declaration_ids">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="tax_regime"/>
<field name="limit"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- Action -->
<record id="action_it_investment_type" model="ir.actions.act_window">
<field name="name">Investment Types</field>
<field name="res_model">it.investment.type</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create the different Investment Types here.
</p>
</field>
</record>
<menuitem id="menu_it_investment_type" name="Investment Types"
parent="menu_it_payroll_declarations"
action="action_it_investment_type" sequence="20"/>
</data>
</odoo>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- <menuitem id="menu_it_tax_statement_root" name="IT Tax Statement" parent="hr.menu_hr_root" sequence="100"/>-->
<record id="view_it_tax_statement_wizard_list" model="ir.ui.view">
<field name="name">it.tax.statement.wizard.list</field>
<field name="model">it.tax.statement.wizard</field>
<field name="arch" type="xml">
<list>
<field name="employee_id"/>
<field name="period_id"/>
<field name="period_line"/>
<field name="tax_regime"/>
</list>
</field>
</record>
<record id="view_it_tax_statement_wizard_form" model="ir.ui.view">
<field name="name">it.tax.statement.wizard.form</field>
<field name="model">it.tax.statement.wizard</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_generate_report"
string="Generate Tax Statement"
type="object"
class="oe_stat_button"
icon="fa-file-text"/>
</header>
<sheet>
<group>
<field name="employee_id" options="{'no_edit': True, 'no_create': True}"/>
<field name="contract_id" readonly="1" force_save="1" invisible="0"/>
</group>
<group>
<field name="taxpayer_age"/>
<field name="residential_status"/>
<field name="parent_age"/>
<field name="emp_doj" force_save="1" invisible="0" readonly="1"/>
</group>
<group>
<group>
<field name="period_id" options="{'no_edit': True, 'no_create': True, 'no_open': True}"/>
</group>
<group>
<field name="period_line" domain="[('period_id', '=', period_id),('to_date','&lt;',datetime.datetime.now()),('from_date','&gt;',emp_doj)]" options="{'no_edit': True, 'no_create': True, 'no_open': True}" invisible="not emp_doj"/>
<field name="period_line" domain="[('period_id', '=', period_id),('to_date','&lt;',datetime.datetime.now())]" options="{'no_edit': True, 'no_create': True, 'no_open': True}" invisible="emp_doj"/>
</group>
</group>
<group>
<field name="tax_regime" nolabel="1" widget="radio" options="{'horizontal': true}" on_change="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_it_tax_statement_wizard" model="ir.actions.act_window">
<field name="name">Generate Tax Statement</field>
<field name="res_model">it.tax.statement.wizard</field>
<field name="path">tax-statement</field>
<field name="view_mode">list,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new employment type
</p>
</field>
</record>
<menuitem id="menu_it_tax_statement_root" name="IT Tax Statement"
parent="hr_payroll.menu_hr_payroll_root"
action="action_it_tax_statement_wizard" sequence="99"/>
<record id="it_statement_paper_format" model="report.paperformat">
<field name="name">A4 - statement</field>
<field name="default" eval="True"/>
<field name="format">A4</field>
<field name="page_height">0</field>
<field name="page_width">0</field>
<field name="orientation">Portrait</field>
<field name="margin_top">10</field>
<field name="margin_bottom">10</field>
<field name="margin_left">7</field>
<field name="margin_right">7</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">10</field>
<field name="dpi">90</field>
</record>
<record id="income_tax_statement_action_report" model="ir.actions.report">
<field name="name">Download Income Tax</field>
<field name="model">it.tax.statement.wizard</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">employee_it_declaration.generate_income_tax_statement_rpt</field>
<field name="report_file">employee_it_declaration.generate_income_tax_statement_rpt</field>
<field name="binding_model_id" ref="employee_it_declaration.model_it_tax_statement_wizard"/>
<field name="print_report_name">'INCOMETAX - %s' % (object.display_name)</field>
<field name="paperformat_id" ref="it_statement_paper_format"/>
<field name="binding_type">report</field>
</record>
</odoo>

View File

@ -0,0 +1,49 @@
<odoo>
<record id="view_payroll_period_form" model="ir.ui.view">
<field name="name">payroll.period.form</field>
<field name="model">payroll.period</field>
<field name="arch" type="xml">
<form string="Payroll Period">
<header>
<button name="action_generate_month_lines" type="object" string="Generate Periods" class="btn-primary"/>
</header>
<sheet>
<group>
<field name="from_date"/>
<field name="to_date"/>
<field name="name" readonly="1" force_save="1"/>
</group>
<field name="period_line_ids">
<list editable="bottom">
<field name="name"/>
<field name="from_date"/>
<field name="to_date"/>
</list>
</field>
</sheet>
</form>
</field>
</record>
<record id="view_payroll_period_tree" model="ir.ui.view">
<field name="name">payroll.period.tree</field>
<field name="model">payroll.period</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="from_date"/>
<field name="to_date"/>
</list>
</field>
</record>
<record id="action_payroll_period" model="ir.actions.act_window">
<field name="name">Payroll Periods</field>
<field name="res_model">payroll.period</field>
<field name="view_mode">list,form</field>
</record>
<menuitem id="menu_it_payroll_declarations" name="Payroll" parent="hr_payroll.menu_hr_payroll_configuration"/>
<menuitem id="menu_payroll_period" name="Payroll Periods" parent="menu_it_payroll_declarations" action="action_payroll_period"/>
</odoo>

View File

@ -0,0 +1,28 @@
<odoo>
<template id="report_it_tax_statement">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<h2>IT Tax Statement</h2>
<p><strong>Employee:</strong> <t t-esc="doc.employee_id.name"/></p>
<p><strong>Period:</strong> <t t-esc="doc.period_id.name"/></p>
<p><strong>Tax Regime:</strong> <t t-esc="dict(doc._fields['tax_regime'].selection).get(doc.tax_regime)"/></p>
<table class="table table-sm">
<thead>
<tr><th>Section</th><th>Amount</th></tr>
</thead>
<tbody>
<t t-foreach="doc.investment_costing_ids" t-as="line">
<tr>
<td><t t-esc="line.investment_type_id.name"/></td>
<td><t t-esc="line.amount"/></td>
</tr>
</t>
</tbody>
</table>
<p><strong>Total:</strong> <t t-esc="sum(doc.investment_costing_ids.mapped('amount'))"/></p>
</div>
</t>
</t>
</template>
</odoo>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Menu Items -->
<menuitem id="menu_it_slab_controller" name="Slab" parent="hr_payroll.menu_hr_payroll_configuration"/>
<!-- Window Action -->
<record id="action_it_slab_master" model="ir.actions.act_window">
<field name="name">Income Tax Slabs</field>
<field name="path">slab-master</field>
<field name="res_model">it.slab.master</field>
<field name="view_mode">list,form</field>
</record>
<menuitem id="menu_it_slab_master_item"
name="Slab Master"
parent="menu_it_slab_controller"
action="action_it_slab_master"/>
<!-- list View -->
<record id="view_it_slab_master_list" model="ir.ui.view">
<field name="name">it.slab.master.list</field>
<field name="model">it.slab.master</field>
<field name="arch" type="xml">
<list>
<field name="name"/>
<field name="regime"/>
<field name="age_category"/>
<field name="residence_type"/>
<field name="standard_deduction"/>
<field name="active"/>
</list>
</field>
</record>
<!-- Form View -->
<record id="view_it_slab_master_form" model="ir.ui.view">
<field name="name">it.slab.master.form</field>
<field name="model">it.slab.master</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<field name="name"/>
<field name="regime"/>
<field name="age_category"/>
<field name="residence_type"/>
<field name="standard_deduction"/>
<field name="active"/>
</group>
<notebook>
<page string="Slab Rules">
<field name="rules">
<list editable="bottom">
<field name="min_income"/>
<field name="max_income"/>
<field name="tax_rate"/>
<field name="fixed_amount"/>
<field name="excess_threshold"/>
<field name="surcharge_rate"/>
<field name="cess_rate"/>
</list>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
</odoo>

View File

@ -0,0 +1,6 @@
from . import children_education_costing
from . import employee_life_insurance
from . import nsc_declaration
from . import self_occupied_property
from . import letout_house_property
from . import nsc_income_loss

View File

@ -0,0 +1,48 @@
from odoo import models, fields, api
class ChildrenEducation(models.Model):
_name = "children.education"
_description = "Children Education"
_rec_name = 'it_declaration_id'
it_declaration_id = fields.Many2one('emp.it.declaration')
children_ids = fields.One2many(
'children.education.costing',
'child_education_id',
string="Children",
)
total_count = fields.Integer(string="Total Tuition Fee", compute="_compute_total_count", store=True)
us80c_id = fields.Many2one('us80c.costing.type')
@api.depends('children_ids.tuition_fee')
def _compute_total_count(self):
for rec in self:
rec.total_count = sum(child.tuition_fee for child in rec.children_ids)
@api.model
def create(self, vals):
record = super().create(vals)
context = self._context or {}
if not record.children_ids:
record.children_ids = [
(0, 0, {'child_id': 'CHILD 1'}),
(0, 0, {'child_id': 'CHILD 2'}),
]
return record
# def write(self, vals):
# print(vals)
# self.us80c_id.declaration_amount = self.total_count if self.us80c_id.limit > self.total_count else self.us80c_id.limit
# return super().write(vals)
class ChildrenEducationCosting(models.Model):
_name = 'children.education.costing'
_description = "Children Education Costing"
child_id = fields.Char('Child ID')
name = fields.Char('Name of Child')
chile_class = fields.Char('Class / Grade')
organization = fields.Char('School / College')
tuition_fee = fields.Integer('Tuition Fee')
child_education_id = fields.Many2one('children.education', string="Education Record", ondelete='cascade')

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- children_education_views.xml -->
<odoo>
<record id="view_children_education_form" model="ir.ui.view">
<field name="name">children.education.form</field>
<field name="model">children.education</field>
<field name="arch" type="xml">
<form string="Children Education">
<sheet>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="us80c_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="total_count" readonly="1"/>
</group>
<field name="children_ids" nolabel="1">
<list editable="bottom" create="0" delete="0">
<field name="child_id" readonly="1" force_save="1"/>
<field name="name"/>
<field name="chile_class"/>
<field name="organization"/>
<field name="tuition_fee"/>
</list>
</field>
</sheet>
</form>
</field>
</record>
<record id="view_children_education_list" model="ir.ui.view">
<field name="name">children.education.list</field>
<field name="model">children.education</field>
<field name="arch" type="xml">
<list>
<field name="it_declaration_id"/>
<field name="total_count"/>
</list>
</field>
</record>
<record id="action_children_education" model="ir.actions.act_window">
<field name="name">Children Education</field>
<field name="res_model">children.education</field>
<field name="view_mode">form</field>
</record>
</odoo>

View File

@ -0,0 +1,52 @@
from odoo import models, fields, api, _
class US80CInsuranceLine(models.Model):
_name = 'us80c.insurance.line'
_description = 'US80C Insurance Line'
it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration")
us80c_id = fields.Many2one('us80c.costing.type', string="80C Costing Type")
life_insurance_ids = fields.One2many(
'employee.life.insurance',
'parent_id',
string="Life Insurance Entries"
)
total_premium_amount = fields.Float(string="Total Premium", compute='_compute_totals', store=True)
total_capital_sum_assured = fields.Float(string="Total Capital Sum Assured", compute='_compute_totals', store=True)
total_max_percentage = fields.Float(string="Total Max %", compute='_compute_totals', store=True)
total_exempt_amount = fields.Float(string="Total Exempt Amount", compute='_compute_totals', store=True)
@api.depends('life_insurance_ids')
def _compute_totals(self):
for rec in self:
rec.total_premium_amount = sum(line.premium_amount for line in rec.life_insurance_ids)
rec.total_capital_sum_assured = sum(line.capital_sum_assured for line in rec.life_insurance_ids)
rec.total_max_percentage = sum(line.max_percentage for line in rec.life_insurance_ids)
rec.total_exempt_amount = sum(line.exempt_amount for line in rec.life_insurance_ids)
class EmployeeLifeInsurance(models.Model):
_name = 'employee.life.insurance'
_description = 'Employee Life Insurance'
parent_id = fields.Many2one('us80c.insurance.line', string="Parent Line") # Link to parent
name_of_insurance_company = fields.Char(string="Name of Insurance Company")
insured_in_favour_of = fields.Selection([
('self', 'Self'),
('spouse', 'Spouse'),
('child', 'Child'),
('dependent', 'Dependent'),
], string="Insured in Favour of")
name_of_insured = fields.Char(string="Name of Insured")
policy_number = fields.Char(string="Policy Number")
premium_amount = fields.Float(string="Premium Amount")
payment_date = fields.Date(string="Payment Date")
capital_sum_assured = fields.Float(string="Capital Sum Assured")
policy_date = fields.Date(string="Policy Date")
max_percentage = fields.Float(string="Max Percentage")
exempt_amount = fields.Float(string="Exempt Amount")

View File

@ -0,0 +1,57 @@
<odoo>
<record id="view_us80c_insurance_line_form" model="ir.ui.view">
<field name="name">us80c.insurance.line.form</field>
<field name="model">us80c.insurance.line</field>
<field name="arch" type="xml">
<form string="US80C Insurance Line">
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="us80c_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<field name="life_insurance_ids">
<list editable="bottom">
<field name="name_of_insurance_company" width="200px"/>
<field name="insured_in_favour_of" width="100px"/>
<field name="name_of_insured" width="150px"/>
<field name="policy_number" width="100px"/>
<field name="premium_amount" width="70px"/>
<field name="payment_date" width="70px"/>
<field name="capital_sum_assured" width="80px"/>
<field name="policy_date" width="70px"/>
<field name="max_percentage" width="70px"/>
<field name="exempt_amount" width="70px"/>
</list>
</field>
<group>
<group>
</group>
<group>
<field name="total_premium_amount" readonly="1"/>
<field name="total_capital_sum_assured" readonly="1"/>
<field name="total_max_percentage" readonly="1"/>
<field name="total_exempt_amount" readonly="1"/>
</group>
</group>
</form>
</field>
</record>
<record id="view_us80c_insurance_line_list" model="ir.ui.view">
<field name="name">us80c.insurance.line.list</field>
<field name="model">us80c.insurance.line</field>
<field name="arch" type="xml">
<list string="Insurance Lines">
<field name="it_declaration_id"/>
<field name="us80c_id"/>
</list>
</field>
</record>
<record id="action_us80c_insurance_line" model="ir.actions.act_window">
<field name="name">Life Insurance</field>
<field name="res_model">us80c.insurance.line</field>
<field name="view_mode">form</field>
</record>
</odoo>

View File

@ -0,0 +1,43 @@
from odoo import models, fields, api
import math
class LetoutHouseProperty(models.Model):
_name = 'letout.house.property'
_description = 'Letout House Property Details'
it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration")
other_il_id = fields.Many2one('other.il.costing.type', string="Other Income/Loss Costing Type")
address = fields.Char(string="Address of Property")
loan_after_april_1999 = fields.Selection([('yes','Yes'),('no','No')],default='yes',
string="House Loan Taken After 01-Apr-1999 & Construction Completed Within 3 Years"
)
rent_received = fields.Integer(string="Rent Received Per Annum")
period_from = fields.Date(string="Period From")
period_to = fields.Date(string="Period To")
property_tax = fields.Integer(string="Less : Property Tax")
water_tax = fields.Integer(string="Less : Water Tax")
net_annual_value = fields.Integer(string="Net Annual Value of the Property", readonly=True)
deduction_for_repairs = fields.Integer(string="Less : Deduction for Repairs 30% if Net Annual Value of the Property", readonly=True)
interest_paid_to = fields.Integer(string="Less : Interest on Borrowed Capital Paid To")
income_loss = fields.Integer(string="Income / Loss on House Property", readonly=True)
lender_name = fields.Char(string="Lender Name")
lender_pan = fields.Char(string="Lender PAN")
@api.onchange('rent_received','property_tax','water_tax','interest_paid_to')
def onchange_property_water_income_tax(self):
for record in self:
net_annual_value = record.rent_received - record.property_tax - record.water_tax
deduction = net_annual_value * 0.30
income_loss = net_annual_value - deduction - record.interest_paid_to
print(net_annual_value)
print(deduction)
print(income_loss)
record.net_annual_value = net_annual_value
record.deduction_for_repairs = round(deduction)
record.income_loss = round(income_loss)

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_letout_house_property_form" model="ir.ui.view">
<field name="name">letout.house.property.form</field>
<field name="model">letout.house.property</field>
<field name="arch" type="xml">
<form string="Letout House Property">
<sheet>
<!-- Header Section -->
<group>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<group>
<field name="other_il_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
</group>
<!-- Property Information -->
<separator string="Property Information" colspan="2"/>
<group>
<field name="address" required="1"/>
</group>
<group>
<div class="oe_row">
<label for="loan_after_april_1999"
string="House Loan Taken After 01-Apr-1999 &amp; Construction Completed Within 3 Years &amp;nbsp;"/>
<field name="loan_after_april_1999" nolabel="1" widget="radio"
options="{'horizontal': true}" class="ml-2" required="1"/>
</div>
</group>
<group>
<!-- Rental and Period Info -->
<group>
<separator string="Rental and Period Info"/>
<field name="rent_received"/>
<field name="period_from" required="1"/>
<field name="period_to" required="1"/>
<br/>
<separator string="Lender Information"/>
<field name="lender_name"/>
<field name="lender_pan"/>
</group>
<!-- Deductions & Value -->
<group string="Deductions and Property Value">
<field name="property_tax"/>
<field name="water_tax"/>
<field name="net_annual_value" readonly="1" force_save="1"/>
<field name="deduction_for_repairs" readonly="1" force_save="1"/>
<field name="interest_paid_to"/>
<field name="income_loss" readonly="1" force_save="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_letout_house_property_list" model="ir.ui.view">
<field name="name">letout.house.property.list</field>
<field name="model">letout.house.property</field>
<field name="arch" type="xml">
<list string="Letout House Property">
<field name="address"/>
<field name="rent_received"/>
<field name="net_annual_value"/>
<field name="income_loss"/>
</list>
</field>
</record>
<record id="action_letout_house_property" model="ir.actions.act_window">
<field name="name">Letout House Property</field>
<field name="res_model">letout.house.property</field>
<field name="view_mode">form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Add a new Letout House Property entry
</p>
</field>
</record>
</odoo>

View File

@ -0,0 +1,27 @@
from odoo import models, fields, api
class NSCDeclarationLine(models.Model):
_name = 'nsc.declaration.line'
_description = 'NSC Declaration Line'
it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration", required=True)
us80c_id = fields.Many2one('us80c.costing.type', string="80C Costing Type", required=True)
nsc_entry_ids = fields.One2many('nsc.entry', 'parent_id', string="NSC Entries")
total_nsc_amount = fields.Float(string="Total NSC Amount", compute="_compute_total_amount", store=True)
@api.depends('nsc_entry_ids.nsc_amount')
def _compute_total_amount(self):
for rec in self:
rec.total_nsc_amount = sum(entry.nsc_amount for entry in rec.nsc_entry_ids)
class NSCEntry(models.Model):
_name = 'nsc.entry'
_description = 'NSC Entry'
parent_id = fields.Many2one('nsc.declaration.line', string="NSC Declaration")
nsc_number = fields.Char(string="NSC Number")
nsc_amount = fields.Float(string="NSC Amount")
nsc_payment_date = fields.Date(string="NSC Payment Date")

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_nsc_declaration_line_form" model="ir.ui.view">
<field name="name">nsc.declaration.line.form</field>
<field name="model">nsc.declaration.line</field>
<field name="arch" type="xml">
<form string="NSC Declaration">
<sheet>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="us80c_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<field name="nsc_entry_ids">
<list editable="bottom">
<field name="nsc_number" width="500px"/>
<field name="nsc_amount"/>
<field name="nsc_payment_date"/>
</list>
</field>
<group>
<group>
</group>
<group>
<field name="total_nsc_amount" readonly="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_nsc_declaration_line_list" model="ir.ui.view">
<field name="name">nsc.declaration.line.list</field>
<field name="model">nsc.declaration.line</field>
<field name="arch" type="xml">
<list>
<field name="it_declaration_id"/>
<field name="us80c_id"/>
<field name="total_nsc_amount"/>
</list>
</field>
</record>
<record id="action_nsc_declaration_line" model="ir.actions.act_window">
<field name="name">NSC Declarations</field>
<field name="res_model">nsc.declaration.line</field>
<field name="view_mode">form</field>
</record>
</odoo>

View File

@ -0,0 +1,32 @@
from odoo import models, fields, api
class NSCInterestLine(models.Model):
_name = 'nsc.interest.line'
_description = 'NSC Interest Line'
it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration", required=True)
other_il_id = fields.Many2one('other.il.costing.type', string="Other Income/Loss Costing Type")
nsc_entry_ids = fields.One2many('nsc.interest.entry', 'parent_id', string="NSC Entries")
total_nsc_amount = fields.Integer(string="Total NSC Amount", compute="_compute_total_amount", store=True)
total_nsc_interest_amount = fields.Integer(string="NSC Interest Amount",compute="_compute_total_amount", store=True)
@api.depends('nsc_entry_ids.nsc_amount')
def _compute_total_amount(self):
for rec in self:
rec.total_nsc_amount = sum(entry.nsc_amount for entry in rec.nsc_entry_ids)
rec.total_nsc_interest_amount = sum(entry.nsc_interest_amount for entry in rec.nsc_entry_ids)
class NSCEntry(models.Model):
_name = 'nsc.interest.entry'
_description = 'NSC Entry'
parent_id = fields.Many2one('nsc.interest.line', string="NSC Interest")
nsc_number = fields.Char(string="NSC Number")
nsc_amount = fields.Integer(string="NSC Amount")
nsc_payment_date = fields.Date(string="NSC Payment Date")
nsc_interest_amount = fields.Integer(string="NSC Interest Amount")

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_nsc_interest_line_form" model="ir.ui.view">
<field name="name">nsc.interest.line.form</field>
<field name="model">nsc.interest.line</field>
<field name="arch" type="xml">
<form string="National Saving Certificate">
<sheet>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
<field name="other_il_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<field name="nsc_entry_ids">
<list editable="bottom">
<field name="nsc_number" width="500px"/>
<field name="nsc_payment_date"/>
<field name="nsc_amount"/>
<field name="nsc_interest_amount"/>
</list>
</field>
<group>
<group>
</group>
<group>
<field name="total_nsc_amount" readonly="1" force_save="1"/>
<field name="total_nsc_interest_amount" readonly="1" force_save="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_nsc_interest_line_list" model="ir.ui.view">
<field name="name">nsc.interest.line.list</field>
<field name="model">nsc.interest.line</field>
<field name="arch" type="xml">
<list>
<field name="it_declaration_id"/>
<field name="other_il_id"/>
<field name="total_nsc_amount"/>
<field name="total_nsc_interest_amount"/>
</list>
</field>
</record>
<record id="action_nsc_interest_line" model="ir.actions.act_window">
<field name="name">NSC Interest</field>
<field name="res_model">nsc.interest.line</field>
<field name="view_mode">form</field>
</record>
</odoo>

View File

@ -0,0 +1,28 @@
from odoo import models, fields, api
class SelfOccupiedProperty(models.Model):
_name = 'self.occupied.property'
_description = 'Self Occupied House Property Details'
it_declaration_id = fields.Many2one('emp.it.declaration', string="IT Declaration")
other_il_id = fields.Many2one('other.il.costing.type', string="Other Income/Loss Costing Type")
address = fields.Text(string="Address of Property")
loan_after_april_1999 = fields.Selection([('yes','Yes'),('no','No')],default='yes',
string="House Loan Taken After 01-Apr-1999 & Construction Completed Within 3 Years"
)
period_from = fields.Date(string="Period From")
period_to = fields.Date(string="Period To")
interest_paid_to = fields.Integer(string="Less: Interest on Borrowed Capital Paid To")
income_loss = fields.Integer(string="Income / Loss on House Property")
lender_name = fields.Char(string="Lender Name")
lender_pan = fields.Char(string="Lender PAN")
@api.onchange('interest_paid_to')
def onchange_interest_paid_to(self):
for rec in self:
rec.income_loss = -(rec.interest_paid_to)

View File

@ -0,0 +1,80 @@
<odoo>
<!-- Form View -->
<record id="view_self_occupied_property_form" model="ir.ui.view">
<field name="name">self.occupied.property.form</field>
<field name="model">self.occupied.property</field>
<field name="arch" type="xml">
<form string="Self Occupied House Property">
<sheet>
<!-- Header Section -->
<group>
<group>
<field name="it_declaration_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
<group>
<field name="other_il_id" readonly="1" force_save="1" options="{'no_open': True, 'no_quick_create': True}"/>
</group>
</group>
<!-- Parent References -->
<!-- Property Info -->
<separator string="Property Information" colspan="2"/>
<group>
<field name="address"/>
</group>
<group>
<div class="oe_row">
<label for="loan_after_april_1999"
string="House Loan Taken After 01-Apr-1999 &amp; Construction Completed Within 3 Years &amp;nbsp; "/>
<field name="loan_after_april_1999" nolabel="1" widget="radio"
options="{'horizontal': true}" class="ml-2"/>
</div>
</group>
<group>
<!-- Period & Interest Info -->
<group string="Period &amp; Interest Details">
<field name="period_from"/>
<field name="period_to"/>
<field name="interest_paid_to"/>
</group>
<!-- Financial & Lender Info -->
<group string="Financial &amp; Lender Information">
<field name="income_loss" readonly="1" force_save="1"/>
<field name="lender_name"/>
<field name="lender_pan"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- list View -->
<record id="view_self_occupied_property_list" model="ir.ui.view">
<field name="name">self.occupied.property.list</field>
<field name="model">self.occupied.property</field>
<field name="arch" type="xml">
<list>
<field name="it_declaration_id"/>
<field name="address"/>
<field name="loan_after_april_1999"/>
<field name="period_from"/>
<field name="period_to"/>
<field name="interest_paid_to"/>
<field name="income_loss"/>
</list>
</field>
</record>
<!-- Action -->
<record id="action_self_occupied_property" model="ir.actions.act_window">
<field name="name">Self Occupied Properties</field>
<field name="res_model">self.occupied.property</field>
<field name="view_mode">form</field>
</record>
</odoo>