Employee it declaration

This commit is contained in:
pranaysaidurga 2026-05-25 16:10:45 +05:30
parent 4db7e5ade2
commit 5460f6c207
8 changed files with 467 additions and 80 deletions

View File

@ -34,7 +34,7 @@
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['base','hr','hr_payroll','hr_employee_extended'],
'depends': ['base','hr','hr_payroll','hr_employee_extended','l10n_in_hr_payroll'],
# always loaded
'data': [
@ -48,14 +48,15 @@
'report/report_action.xml',
'report/it_tax_template.xml',
'views/it_tax_menu_and_wizard_view.xml',
'wizards/hr_tds_calculation.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',
'data/default_investment_types.xml',
# 'views/it_investment_type.xml',
# 'views/it_investment_costing.xml'
],
}
'wizards/self_occupied_property.xml',
'wizards/letout_house_property.xml',
'wizards/nsc_income_loss.xml',
'data/default_investment_types.xml',
# 'views/it_investment_type.xml',
# 'views/it_investment_costing.xml'
],
}

View File

@ -18,9 +18,9 @@ class ITTaxStatementWizard(models.TransientModel):
contract_id = fields.Many2one('hr.contract', related='employee_id.contract_id', required=True)
currency_id = fields.Many2one('res.currency', related='employee_id.company_id.currency_id')
period_id = fields.Many2one('payroll.period', required=True)
period_line = fields.Many2one('payroll.period.line',
domain="[('period_id', '=', period_id), ('to_date', '<', fields.Date.today())]")
period_id = fields.Many2one('payroll.period', required=True)
period_line = fields.Many2one('payroll.period.line',
domain="[('period_id', '=', period_id), ('to_date', '<', fields.Date.today())]")
# Taxpayer profile
taxpayer_name = fields.Char(related='employee_id.name')
@ -96,12 +96,32 @@ class ITTaxStatementWizard(models.TransientModel):
('new', 'New Regime')
], string="Beneficial Regime", readonly=True)
def _get_age_category(self, age):
if age < 60:
return 'below_60'
elif age < 80:
return '60_to_80'
return 'above_80'
def _get_age_category(self, age):
if age < 60:
return 'below_60'
elif age < 80:
return '60_to_80'
return 'above_80'
def _get_effective_period_start(self):
self.ensure_one()
period_start = self.period_id.from_date if self.period_id else False
if not period_start:
return False
if self.emp_doj and self.period_id.to_date and self.period_id.from_date <= self.emp_doj <= self.period_id.to_date:
return max(period_start, self.emp_doj.replace(day=1))
return period_start
def _get_effective_period_lines(self):
self.ensure_one()
if not self.period_id:
return self.env['payroll.period.line']
period_lines = self.period_id.period_line_ids.sorted('from_date')
effective_start = self._get_effective_period_start()
if not effective_start:
return period_lines
return period_lines.filtered(lambda line: line.to_date and line.to_date >= effective_start)
def _find_applicable_slab(self, regime, period_id, age, residence_type):
"""Find the applicable tax slab without forcing both regimes to exist."""
@ -116,7 +136,7 @@ class ITTaxStatementWizard(models.TransientModel):
('residence_type', '=', 'both')
], limit=1)
def _get_applicable_slab(self, regime, period_id, age, residence_type):
def _get_applicable_slab(self, regime, period_id, age, residence_type):
"""Get the applicable tax slab based on regime, age, and residence type"""
age_category = self._get_age_category(age)
slab_master = self._find_applicable_slab(regime, period_id, age, residence_type)
@ -125,7 +145,21 @@ class ITTaxStatementWizard(models.TransientModel):
"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
return slab_master
@api.onchange('employee_id', 'period_id')
def _onchange_employee_id_period_id(self):
domain_by_record = {}
for rec in self:
domain = [('period_id', '=', rec.period_id.id), ('to_date', '<', fields.Date.today())] if rec.period_id else []
if rec.emp_doj:
domain.append(('to_date', '>=', rec.emp_doj.replace(day=1)))
if rec.period_line and rec.period_line not in rec._get_effective_period_lines():
rec.period_line = False
domain_by_record[rec.id] = domain
if len(self) == 1:
return {'domain': {'period_line': domain_by_record.get(self.id, [])}}
def _get_standard_deduction(self, regime, slab_master=False):
if slab_master:
@ -295,7 +329,7 @@ class ITTaxStatementWizard(models.TransientModel):
return list(grouped.values())
def fetch_salary_components(self):
def fetch_salary_components(self):
"""fetch salary components from payroll data"""
for rec in self:
data = {
@ -311,10 +345,10 @@ class ITTaxStatementWizard(models.TransientModel):
}
if not rec.employee_id or not rec.contract_id or not rec.period_id or not rec.period_line:
return data
period_lines = rec.period_id.period_line_ids
for line in period_lines:
components = rec._get_salary_components_for_period_line(line)
period_lines = rec._get_effective_period_lines()
for line in period_lines:
components = rec._get_salary_components_for_period_line(line)
if line.from_date and rec.period_line.from_date and line.from_date <= rec.period_line.from_date:
data['basic_salary']['actual'].append(components['basic_salary'])
data['hra_salary']['actual'].append(components['hra_salary'])
@ -378,7 +412,7 @@ class ITTaxStatementWizard(models.TransientModel):
)
rec.standard_deduction = rec._get_standard_deduction(rec.tax_regime, slab_master)
def fetch_deduction_components(self):
def fetch_deduction_components(self):
for rec in self:
data = {
'professional_tax': {'actual': [], 'projected': []},
@ -387,12 +421,12 @@ class ITTaxStatementWizard(models.TransientModel):
if not rec.employee_id or not rec.contract_id or not rec.period_id or not rec.period_line:
return data
for line in rec.period_id.period_line_ids:
rule_amounts = rec._get_rule_amounts_for_period_line(line, ['PT', 'PFE'])
bucket = 'actual' if line.from_date <= rec.period_line.from_date else 'projected'
data['professional_tax'][bucket].append(rule_amounts['PT'])
data['nps_employer_contribution'][bucket].append(rule_amounts['PFE'])
return data
for line in rec._get_effective_period_lines():
rule_amounts = rec._get_rule_amounts_for_period_line(line, ['PT', 'PFE'])
bucket = 'actual' if line.from_date <= rec.period_line.from_date else 'projected'
data['professional_tax'][bucket].append(rule_amounts['PT'])
data['nps_employer_contribution'][bucket].append(rule_amounts['PFE'])
return data
@api.onchange('employee_id')
@ -725,25 +759,19 @@ class ITTaxStatementWizard(models.TransientModel):
'target': 'current',
}
def _prepare_income_tax_data(self, include_comparison=False):
"""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)
values = self._get_tax_base_values(include_comparison=include_comparison)
def _prepare_income_tax_data(self, include_comparison=False):
"""Prepare data for the tax statement report"""
today = date.today()
display_fy_start = self.period_id.from_date
fy_end = self.period_id.to_date
effective_fy_start = self._get_effective_period_start() or display_fy_start
total_months = ((fy_end.year - effective_fy_start.year) * 12 +
(fy_end.month - effective_fy_start.month) + 1)
line_start = self.period_line.from_date
current_month_index = ((line_start.year - effective_fy_start.year) * 12 +
(line_start.month - effective_fy_start.month) + 1)
values = self._get_tax_base_values(include_comparison=include_comparison)
salary_components_data = values['salary_components_data']
annual_gross_salary = values['annual_gross_salary']
gross_salary_actual = values['gross_salary_actual']
@ -778,15 +806,16 @@ class ITTaxStatementWizard(models.TransientModel):
# 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)
display_fy_start = self.period_id.from_date
fy_end = self.period_id.to_date
effective_fy_start = self._get_effective_period_start() or display_fy_start
total_months = ((fy_end.year - effective_fy_start.year) * 12 +
(fy_end.month - effective_fy_start.month) + 1)
# Current month (period_line)
line_start = self.period_line.from_date
current_month_index = ((line_start.year - effective_fy_start.year) * 12 +
(line_start.month - effective_fy_start.month) + 1)
tax_result['roundoff_taxable_income'] = float(round(tax_result["taxable_income"] / 10) * 10)
birthday = self.employee_id.birthday
if birthday:
@ -806,7 +835,7 @@ class ITTaxStatementWizard(models.TransientModel):
'total': total,
})
data = {
'financial_year': f"{fy_start.year}-{fy_end.year}",
'financial_year': f"{display_fy_start.year}-{fy_end.year}",
'assessment_year': fy_end.year + 1,
'report_time': today.strftime('%d-%m-%Y %H:%M'),
'user': 'ESS',

View File

@ -13,17 +13,17 @@ class IncomeTaxSlabMaster(models.Model):
)
]
name = fields.Char(string="Slab Name", required=True)
period_id = fields.Many2one('payroll.period')
name = fields.Char(string="Slab Name", required=True, copy=False, default="AY")
period_id = fields.Many2one('payroll.period', copy=False)
regime = fields.Selection([
('old', 'Old Tax Regime'),
('new', 'New Tax Regime')
], required=True)
], required=True, default='old')
age_category = fields.Selection([
('below_60', 'Below 60 Years'),
('60_to_80', '60-80 Years'),
('above_80', 'Above 80 Years')
], required=True)
], required=True, default='below_60')
residence_type = fields.Selection([
('resident', 'Resident'),
('non_resident', 'Non Resident'),
@ -34,6 +34,37 @@ class IncomeTaxSlabMaster(models.Model):
rules = fields.One2many('it.slab.master.rules','slab_id', string="Slab Rules")
surcharges = fields.One2many('it.sur.charge.rules','slab_id', string="Surcharges Rules")
def copy(self, default=None):
"""Override copy to duplicate slab rules and surcharge rules"""
if default is None:
default = {}
# Check if we should duplicate from context
duplicate_rules = self.env.context.get('duplicate_slab_rules', True)
default.update({
'name': _("%s (copy)") % (self.name or 'Slab'),
'rules': [],
'surcharges': [],
})
new_slab = super(IncomeTaxSlabMaster, self).copy(default)
# Only duplicate if flag is True
if duplicate_rules:
if self.rules:
for rule in self.rules:
rule.copy({
'slab_id': new_slab.id,
})
if self.surcharges:
for surcharge in self.surcharges:
surcharge.copy({
'slab_id': new_slab.id,
})
return new_slab
class IncomeTaxSlabMasterRules(models.Model):
_name = 'it.slab.master.rules'
_description = 'Income Tax slab rules'

View File

@ -21,19 +21,19 @@
<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"/>
<button name="action_check_regime_comparison"
string="Check Comparison"
type="object"
class="oe_stat_button"
icon="fa-calculator"/>
<button name="action_generate_comparison_report"
string="Download Comparison"
type="object"
<button name="action_generate_report"
string="Generate Tax Statement"
type="object"
class="oe_stat_button"
icon="fa-file-text"/>
<button name="action_check_regime_comparison"
string="Check Comparison"
type="object"
class="oe_stat_button"
icon="fa-calculator"/>
<button name="action_generate_comparison_report"
string="Download Comparison"
type="object"
class="oe_stat_button"
icon="fa-balance-scale"
invisible="not comparison_available"/>
@ -57,7 +57,7 @@
<field name="period_id" options="{'no_edit': True, 'no_create': True, 'no_open': True}"/>
</group>
<group>
<field name="period_line" force_save="1" domain="[('period_id', '=', period_id),('to_date','&lt;',datetime.datetime.now())]"/>
<field name="period_line" force_save="1" domain="[('period_id', '=', period_id),('to_date','&lt;',(context_today() + datetime.timedelta(days=30)).strftime('%Y-%m-%d')),('to_date','&gt;',emp_doj)]"/>
</group>
</group>
<group>

View File

@ -66,7 +66,7 @@
</field>
</page>
<page string="Surcharge Rules">
<field name="rules">
<field name="surcharges">
<list editable="bottom">
<field name="min_income"/>
<field name="max_income"/>

View File

@ -1,3 +1,4 @@
from . import hr_tds_calculation
from . import children_education_costing
from . import employee_life_insurance
from . import nsc_declaration

View File

@ -0,0 +1,308 @@
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class HrTdsCalculation(models.TransientModel):
_inherit = 'l10n.in.tds.computation.wizard'
def default_get(self, fields):
res = super().default_get(fields)
# Remove the standard_deduction if it was set by parent
if 'standard_deduction' in res:
del res['standard_deduction']
return res
tax_regime = fields.Selection([
('new', 'New Regime'),
('old', 'Old Regime')
], string="Tax Regime", required=True, default='new')
standard_deduction = fields.Float(
string="Standard Deduction",
compute="_compute_standard_deduction",
readonly=True,
)
def _get_regular_pay_structure(self):
self.ensure_one()
if self.payslip_id and self.payslip_id.struct_id:
return self.payslip_id.struct_id
if self.contract_id.structure_type_id.default_struct_id:
return self.contract_id.structure_type_id.default_struct_id
return self.env['hr.payroll.structure']
def _get_annualization_factor(self):
self.ensure_one()
if self.contract_id:
return self.contract_id._get_salary_costs_factor()
return 12
def _get_monthly_gross_from_structure(self):
self.ensure_one()
if not self.contract_id or not self.contract_id.employee_id:
return 0.0
structure = self._get_regular_pay_structure()
payslip = self.payslip_id
dummy_payslip = self.env['hr.payslip']
if not payslip:
today = fields.Date.today()
period_start = today.replace(day=1)
period_end = fields.Date.end_of(period_start, 'month')
dummy_payslip = self.env['hr.payslip'].sudo().create({
'name': 'TDS Gross Preview',
'employee_id': self.contract_id.employee_id.id,
'contract_id': self.contract_id.id,
'struct_id': structure.id or self.contract_id.structure_type_id.default_struct_id.id,
'date_from': period_start,
'date_to': period_end,
})
dummy_payslip.sudo().compute_sheet()
payslip = dummy_payslip
try:
gross_lines = payslip.line_ids.filtered(lambda line: line.salary_rule_id.code == 'GROSS')
if gross_lines:
return sum(gross_lines.mapped('total'))
return self.contract_id.wage or 0.0
finally:
if dummy_payslip:
dummy_payslip.sudo().action_payslip_cancel()
dummy_payslip.sudo().unlink()
def _get_current_payroll_period(self):
today = fields.Date.today()
return self.env['payroll.period'].search([
('from_date', '<=', today),
('to_date', '>=', today),
], limit=1)
def _get_age_category(self, age):
if age < 60:
return 'below_60'
if age < 80:
return '60_to_80'
return 'above_80'
def _get_employee_age(self):
self.ensure_one()
employee = self.contract_id.employee_id
if employee and employee.birthday:
return relativedelta(date.today(), employee.birthday).years
return 30
def _find_applicable_slab(self, regime):
self.ensure_one()
period = self._get_current_payroll_period()
if not period:
return self.env['it.slab.master']
age_category = self._get_age_category(self._get_employee_age())
return self.env['it.slab.master'].search([
('period_id', '=', period.id),
('regime', '=', regime),
('age_category', '=', age_category),
'|',
('residence_type', '=', 'resident'),
('residence_type', '=', 'both'),
], limit=1)
def _get_standard_deduction_amount(self, regime, slab_master=False):
if slab_master and slab_master.standard_deduction:
return slab_master.standard_deduction
return 75000.0 if regime == 'new' else 50000.0
def _compute_tax_using_slab(self, taxable_income, slab_master):
rules = slab_master.rules.sorted(lambda r: (r.sequence, r.max_income or float('inf')))
applicable_rule = False
previous_rules = self.env['it.slab.master.rules']
for rule in rules:
min_income = rule.min_income or 0.0
max_income = rule.max_income or float('inf')
if min_income < taxable_income <= max_income:
applicable_rule = rule
previous_rules = rules.filtered(
lambda r: r.sequence < rule.sequence or
(r.sequence == rule.sequence and (r.max_income or float('inf')) < max_income)
)
break
if not applicable_rule:
return 0.0
previous_max_income = previous_rules[-1].max_income if previous_rules else 0.0
current_tax = (taxable_income - previous_max_income) * (applicable_rule.tax_rate / 100.0)
previous_fixed_amounts = sum(previous_rules.mapped('fixed_amount'))
return current_tax + previous_fixed_amounts
def _compute_rebate(self, regime, taxable_income, slab_tax):
if regime == 'old':
if taxable_income <= 500000.0:
return min(12500.0, slab_tax)
return 0.0
if taxable_income >= 1200000.0:
return max(0.0, slab_tax - (taxable_income - 1200000.0))
return min(60000.0, slab_tax)
def _compute_surcharge(self, slab_master, taxable_income, tax_after_rebate):
surcharge_rate = 0.0
for rule in slab_master.surcharges.sorted('min_income'):
max_income = rule.max_income or float('inf')
if rule.min_income < taxable_income <= max_income:
surcharge_rate = rule.surcharge_rate
return tax_after_rebate * (surcharge_rate / 100.0)
def _compute_cess(self, slab_master, taxable_income, tax_with_surcharge):
cess_rate = 4.0
for rule in slab_master.rules.sorted('min_income'):
max_income = rule.max_income or float('inf')
if rule.min_income < taxable_income <= max_income:
cess_rate = rule.cess_rate or 4.0
break
return tax_with_surcharge * (cess_rate / 100.0)
def _compute_tax_from_custom_slab(self, total_income, regime, slab_master):
taxable_income = max(total_income - self._get_standard_deduction_amount(regime, slab_master), 0.0)
slab_tax = self._compute_tax_using_slab(taxable_income, slab_master)
rebate = self._compute_rebate(regime, taxable_income, slab_tax)
total_tax_on_income = max(0.0, slab_tax - rebate)
surcharge = self._compute_surcharge(slab_master, taxable_income, total_tax_on_income)
tax_with_surcharge = total_tax_on_income + surcharge
cess = self._compute_cess(slab_master, taxable_income, tax_with_surcharge) if tax_with_surcharge else 0.0
return {
'taxable_income': taxable_income,
'tax_on_taxable_income': slab_tax,
'rebate': rebate,
'total_tax_on_income': total_tax_on_income,
'surcharge': surcharge,
'cess': cess,
'total_tax': tax_with_surcharge + cess,
}
def _compute_tax_from_rule_parameters(self, total_income, standard_deduction):
rule_parameter = self.env['hr.rule.parameter']
tax_slabs = rule_parameter._get_parameter_from_code('l10n_in_tds_rate_chart')
tax_slabs_for_surcharge = rule_parameter._get_parameter_from_code('l10n_in_surcharge_rate')
min_income_for_surcharge = rule_parameter._get_parameter_from_code('l10n_in_min_income_surcharge')
min_income_for_rebate = rule_parameter._get_parameter_from_code('l10n_in_min_income_tax_rebate')
taxable_income = max(total_income - standard_deduction, 0.0)
tax = 0.0
for rate, (lower, upper) in tax_slabs:
if taxable_income <= lower:
break
taxable_amount = min(taxable_income, float(upper)) - lower
tax += round(taxable_amount * rate)
if taxable_income >= min_income_for_rebate:
marginal_income = taxable_income - min_income_for_rebate
rebate = max(tax - marginal_income, 0.0)
else:
rebate = tax
total_tax_on_income = tax - rebate
surcharge = 0.0
if taxable_income > min_income_for_surcharge:
for rate, amount in tax_slabs_for_surcharge:
if taxable_income <= float(amount[1]):
surcharge = total_tax_on_income * rate
break
max_tax_slabs = rule_parameter._get_parameter_from_code('l10n_in_max_surcharge_tax_rate')
max_taxable_income, max_tax, max_surcharge = 0.0, 0.0, 0.0
for income, tax_amount, surcharge_rate in max_tax_slabs:
if taxable_income <= income:
break
max_taxable_income, max_tax, max_surcharge = income, tax_amount, surcharge_rate
excess_income = taxable_income - max_taxable_income
max_tax_with_surcharge = max_tax + max_surcharge
total_tax_with_surcharge = total_tax_on_income + surcharge
excess_tax = total_tax_with_surcharge - max_tax_with_surcharge
if excess_tax - excess_income > 0:
surcharge = max_tax_with_surcharge + taxable_income - max_taxable_income - total_tax_on_income
cess = (total_tax_on_income + surcharge) * 0.04
return {
'taxable_income': taxable_income,
'tax_on_taxable_income': tax,
'rebate': rebate,
'total_tax_on_income': total_tax_on_income,
'surcharge': surcharge,
'cess': cess,
'total_tax': total_tax_on_income + surcharge + cess,
}
@api.depends('contract_id', 'payslip_id', 'contract_id.structure_type_id', 'contract_id.wage')
def _compute_total_income(self):
for record in self:
if not record.contract_id:
record.total_income = 0.0
continue
monthly_gross = record._get_monthly_gross_from_structure()
rule_parameter = self.env['hr.rule.parameter']
pf = 0
if record.contract_id:
amounts = rule_parameter._get_parameter_from_code('l10n_in_professional_tax')
cost = record.contract_id.wage -1800
if cost >= 20000:
pf = amounts[0]
elif cost >= 15001 and cost < 20000:
pf = amounts[1]
else:
pf = 0
record.total_income = (monthly_gross * record._get_annualization_factor()) + (pf * 12)
@api.depends('contract_id', 'payslip_id', 'total_income')
def _compute_net_monthly(self):
for record in self:
factor = record._get_annualization_factor() if record.contract_id else 12
if record.payslip_id and record.payslip_id.net_wage:
record.net_monthly = record.payslip_id.net_wage
elif factor:
record.net_monthly = record.total_income / factor
else:
record.net_monthly = 0.0
@api.depends('tax_regime', 'contract_id')
def _compute_standard_deduction(self):
for record in self:
slab_master = record._find_applicable_slab(record.tax_regime) if record.tax_regime else False
record.standard_deduction = record._get_standard_deduction_amount(record.tax_regime or 'new', slab_master)
@api.depends('total_income', 'tax_regime', 'standard_deduction', 'contract_id')
def _compute_taxable_income(self):
for record in self:
if not record.total_income:
record.taxable_income = 0.0
record.tax_on_taxable_income = 0.0
record.rebate = 0.0
record.total_tax_on_income = 0.0
record.surcharge = 0.0
record.cess = 0.0
record.total_tax = 0.0
continue
slab_master = record._find_applicable_slab(record.tax_regime) if record.tax_regime else False
if slab_master:
values = record._compute_tax_from_custom_slab(record.total_income, record.tax_regime, slab_master)
else:
values = record._compute_tax_from_rule_parameters(record.total_income, record.standard_deduction)
record.taxable_income = values['taxable_income']
record.tax_on_taxable_income = values['tax_on_taxable_income']
record.rebate = values['rebate']
record.total_tax_on_income = values['total_tax_on_income']
record.surcharge = values['surcharge']
record.cess = values['cess']
record.total_tax = values['total_tax']

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="l10n_in_tds_computation_wizard_view_form_inherit" model="ir.ui.view">
<field name="name">l10n.in.tds.computation.wizard.view.form</field>
<field name="model">l10n.in.tds.computation.wizard</field>
<field name="inherit_id" ref="l10n_in_hr_payroll.l10n_in_tds_computation_wizard_view_form"/>
<field name="arch" type="xml">
<xpath expr="//form/group/field[@name='total_income']" position="after">
<field name="tax_regime" widget="radio" options="{'horizontal': true}"/>
</xpath>
<xpath expr="//form/group/field[@name='standard_deduction']" position="attributes">
<attribute name="force_save">1</attribute>
</xpath>
</field>
</record>
</odoo>