|
| 1 | +from odoo import api, fields, models |
| 2 | + |
| 3 | +class HrTdsDeclarationDetails(models.Model): |
| 4 | + _name = "hr.tds.declaration.details" |
| 5 | + _description = "Hr TDS declaration details for genearated employees" |
| 6 | + |
| 7 | + name = fields.Char(string="Tax Declarations") |
| 8 | + tds_declaration_id = fields.Many2one("hr.tds.declaration", string="TDS Declaration") |
| 9 | + employee_id = fields.Many2one("hr.employee") |
| 10 | + contract_id = fields.Many2one("hr.contract", string="Contract") |
| 11 | + start_date = fields.Date(string="Start Date") |
| 12 | + end_date = fields.Date(string="End Date") |
| 13 | + financial_year = fields.Char(string="Financial Year") |
| 14 | + state = fields.Selection( |
| 15 | + selection= [ |
| 16 | + ("new", "New"), |
| 17 | + ("verify", "Confirmed"), |
| 18 | + ("approve", "Approved"), |
| 19 | + ("cancel", "Cancelled") |
| 20 | + ], |
| 21 | + string="Status", |
| 22 | + default="new" |
| 23 | + ) |
| 24 | + tax_regime = fields.Selection( |
| 25 | + selection= [ |
| 26 | + ("new_regime", "New Regime"), |
| 27 | + ("old_regiem", "Old Regime") |
| 28 | + ], |
| 29 | + string="Tax Regime", |
| 30 | + default="new_regime" |
| 31 | + ) |
| 32 | + age_category = fields.Selection( |
| 33 | + selection= [ |
| 34 | + ("lt60", "Less Than 60"), |
| 35 | + ("60to80", "60 - 80"), |
| 36 | + ("gt80", "Above 80") |
| 37 | + ], |
| 38 | + string="Category (Age)", |
| 39 | + default="lt60" |
| 40 | + ) |
| 41 | + currency_id = fields.Many2one("res.currency", default=lambda self: self.env.company.currency_id.id) |
| 42 | + total_income = fields.Monetary(string="Total Income (yearly)", compute="_compute_total_income", inverse="_inverse_total_income", readonly=False, store=True) |
| 43 | + standard_deduction = fields.Monetary(string="Standard Deducation", compute="_compute_standard_deduction", readonly=True) |
| 44 | + taxable_amount = fields.Monetary(string="Taxable Amount", compute="_compute_taxable_amount") |
| 45 | + tax_on_taxable_amount = fields.Monetary(string="Tax On Taxable Amount", compute="_compute_taxable_amount") |
| 46 | + rebate = fields.Monetary(string="Rebate Under Section 87A(a)", compute="_compute_taxable_amount") |
| 47 | + total_tax_on_income = fields.Monetary(string="Total Tax On Income", compute="_compute_taxable_amount") |
| 48 | + surcharge = fields.Monetary(string="Surcharge", compute="_compute_taxable_amount") |
| 49 | + health_education_cess = fields.Monetary(string="Health and Education Cess", compute="_compute_taxable_amount") |
| 50 | + total_tax_to_pay = fields.Monetary(string="Total Tax to be Paid", compute="_compute_taxable_amount") |
| 51 | + monthly_tds = fields.Monetary(string="Monthly TDS Payable", compute="_compute_monthly_tds") |
| 52 | + other_income_source = fields.Monetary(string="Other Source of Income") |
| 53 | + other_allowance = fields.Monetary(string="Other Allowance Details") |
| 54 | + #Below field is used to store manually added Total Income to ensure that while modifying other_income_source & other_allowance values are reflecting in correct manner into Total Income |
| 55 | + manually_added_total_income = fields.Float() |
| 56 | + |
| 57 | + @api.depends("other_income_source", "other_allowance") |
| 58 | + def _compute_total_income(self): |
| 59 | + for record in self: |
| 60 | + if record.manually_added_total_income and record.total_income: |
| 61 | + record.total_income = record.manually_added_total_income + record.other_income_source + record.other_allowance |
| 62 | + else: |
| 63 | + record.total_income = (record.contract_id.wage * 12 if record.contract_id.wage else 0) + record.other_income_source + record.other_allowance |
| 64 | + |
| 65 | + def _inverse_total_income(self): |
| 66 | + for record in self: |
| 67 | + if record.total_income != (record.contract_id.wage * 12 if record.contract_id.wage else 0) + record.other_income_source + record.other_allowance: |
| 68 | + record.manually_added_total_income = record.total_income |
| 69 | + record.total_income += record.other_income_source + record.other_allowance |
| 70 | + |
| 71 | + |
| 72 | + def _compute_standard_deduction(self): |
| 73 | + for record in self: |
| 74 | + record.standard_deduction = record.env['hr.rule.parameter']._get_parameter_from_code('l10n_in_standard_deduction_new_regime') |
| 75 | + |
| 76 | + @api.depends("total_income") |
| 77 | + def _compute_taxable_amount(self): |
| 78 | + """Computes the taxable amount, tax, rebate, surcharge, and total tax payable |
| 79 | + based on predefined tax slabs and thresholds. |
| 80 | +
|
| 81 | + - Calculates `taxable_amount` after standard deductions. |
| 82 | + - Determines tax liability using progressive tax slabs. |
| 83 | + - Applies rebate if income is below the rebate threshold. |
| 84 | + - Computes surcharge for incomes exceeding the surcharge threshold. |
| 85 | + - Ensures surcharge does not exceed legal limits. |
| 86 | + - Adds health & education cess (4%) to derive total tax payable. |
| 87 | + """ |
| 88 | + rule_parameter = self.env['hr.rule.parameter'] |
| 89 | + tax_slabs = rule_parameter._get_parameter_from_code('l10n_in_tds_rate_chart_new_regime') |
| 90 | + tax_slabs_for_surcharge = rule_parameter._get_parameter_from_code('l10n_in_surcharge_rate') |
| 91 | + min_income_for_surcharge = rule_parameter._get_parameter_from_code('l10n_in_min_income_surcharge') |
| 92 | + min_income_for_rebate = rule_parameter._get_parameter_from_code('l10n_in_min_income_tax_rebate') |
| 93 | + |
| 94 | + for record in self: |
| 95 | + record.taxable_amount = max(record.total_income - record.standard_deduction, 0) |
| 96 | + |
| 97 | + tax = 0 |
| 98 | + for rate, (lower, upper), fixed_tax in tax_slabs: |
| 99 | + if record.taxable_amount >= lower and record.taxable_amount <= upper: |
| 100 | + taxable_amount_temp = record.taxable_amount - lower |
| 101 | + tax = fixed_tax + round(taxable_amount_temp * rate) |
| 102 | + record.tax_on_taxable_amount = tax |
| 103 | + |
| 104 | + if record.taxable_amount >= min_income_for_rebate: |
| 105 | + marginal_income = record.taxable_amount - min_income_for_rebate |
| 106 | + record.rebate = max(record.tax_on_taxable_amount - marginal_income, 0) |
| 107 | + else: |
| 108 | + record.rebate = record.tax_on_taxable_amount |
| 109 | + record.total_tax_on_income = record.tax_on_taxable_amount - record.rebate |
| 110 | + |
| 111 | + if record.taxable_amount > min_income_for_surcharge: |
| 112 | + surcharge = 0 |
| 113 | + for rate, amount in tax_slabs_for_surcharge: |
| 114 | + if record.taxable_amount <= float(amount[1]): |
| 115 | + surcharge = record.total_tax_on_income * rate |
| 116 | + break |
| 117 | + |
| 118 | + max_tax_slabs = rule_parameter._get_parameter_from_code('l10n_in_max_surcharge_tax_rate') |
| 119 | + max_taxable_income, max_tax, max_surcharge = 0, 0, 0 |
| 120 | + |
| 121 | + for income, tax, surcharge_rate in max_tax_slabs: |
| 122 | + if record.taxable_amount <= income: |
| 123 | + break |
| 124 | + else: |
| 125 | + max_taxable_income, max_tax, max_surcharge = income, tax, surcharge_rate |
| 126 | + |
| 127 | + excess_income = record.taxable_amount - max_taxable_income |
| 128 | + max_tax_with_surcharge = max_tax + max_surcharge |
| 129 | + total_tax_with_surcharge = record.total_tax_on_income + surcharge |
| 130 | + excess_tax = total_tax_with_surcharge - max_tax_with_surcharge |
| 131 | + |
| 132 | + if excess_tax - excess_income > 0: |
| 133 | + record.surcharge = max_tax_with_surcharge + record.taxable_amount - max_taxable_income - record.total_tax_on_income |
| 134 | + else: |
| 135 | + record.surcharge = surcharge |
| 136 | + else: |
| 137 | + record.surcharge = 0.0 |
| 138 | + |
| 139 | + record.health_education_cess = (record.total_tax_on_income + record.surcharge) * 0.04 |
| 140 | + record.total_tax_to_pay = record.total_tax_on_income + record.health_education_cess + record.surcharge |
| 141 | + |
| 142 | + @api.depends("total_tax_to_pay") |
| 143 | + def _compute_monthly_tds(self): |
| 144 | + for record in self: |
| 145 | + record.monthly_tds = record.total_tax_to_pay / 12 |
| 146 | + |
| 147 | + def action_tds_declaration_confirm(self): |
| 148 | + if self.state == "new": |
| 149 | + self.state = "verify" |
| 150 | + |
| 151 | + def action_tds_declaration_approve(self): |
| 152 | + if self.state in ("new", "verify"): |
| 153 | + self.state = "approve" |
| 154 | + |
| 155 | + def action_tds_declaration_cancel(self): |
| 156 | + if self.state not in ("cancel"): |
| 157 | + self.state = "cancel" |
| 158 | + |
| 159 | + def action_print_tds_declaration(self): |
| 160 | + return self.env.ref('hr_payroll_tds.action_report_tds_declaration').report_action(self.id) |
0 commit comments