Fix tax calculation (#14635)

* Salary Detail - field is_additional_component

* TDS fix - exclude additional component from monthly salary, but add to annual income to calculate tax

* fix indentation
This commit is contained in:
Ranjith Kurungadam 2018-06-22 15:39:49 +05:30 committed by Nabin Hait
parent 4e96f55eff
commit ce26610d39
5 changed files with 115 additions and 53 deletions

View File

@ -66,6 +66,7 @@ def get_additional_salary_component(employee, start_date, end_date):
struct_row['do_not_include_in_total'] = salary_component.do_not_include_in_total
struct_row['is_tax_applicable'] = salary_component.is_tax_applicable
struct_row['variable_based_on_taxable_salary'] = salary_component.variable_based_on_taxable_salary
struct_row['is_additional_component'] = salary_component.is_additional_component
additional_components_dict['amount'] = amount
additional_components_dict['struct_row'] = struct_row
additional_components_dict['type'] = salary_component.type

View File

@ -211,6 +211,40 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fetch_from": "salary_component.is_additional_component",
"fieldname": "is_additional_component",
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Is Additional Component",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@ -591,7 +625,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-06-05 13:11:04.078930",
"modified": "2018-06-22 12:31:55.516982",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Detail",
@ -606,4 +640,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}
}

View File

@ -12,7 +12,7 @@ frappe.ui.form.on("Salary Slip", {
{fieldname: 'amount', columns: 4}
];
})
frm.fields_dict["timesheets"].grid.get_field("time_sheet").get_query = function(){
return {
filters: {
@ -69,7 +69,7 @@ frappe.ui.form.on("Salary Slip", {
frm.trigger("toggle_fields")
frm.trigger("toggle_reqd_fields")
var salary_detail_fields = ["formula", "abbr", "statistical_component", "is_tax_applicable",
"is_flexible_benefit", "variable_based_on_taxable_salary"]
"is_flexible_benefit", "variable_based_on_taxable_salary", "is_additional_component"]
cur_frm.fields_dict['earnings'].grid.set_column_disp(salary_detail_fields,false);
cur_frm.fields_dict['deductions'].grid.set_column_disp(salary_detail_fields,false);
},

View File

@ -114,7 +114,8 @@ class SalarySlip(TransactionBase):
'do_not_include_in_total' : struct_row.do_not_include_in_total,
'is_tax_applicable': struct_row.is_tax_applicable,
'is_flexible_benefit': struct_row.is_flexible_benefit,
'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary
'variable_based_on_taxable_salary': struct_row.variable_based_on_taxable_salary,
'is_additional_component': struct_row.is_additional_component
})
else:
component_row.amount = amount
@ -526,18 +527,18 @@ class SalarySlip(TransactionBase):
# get all untaxed benefits till date, pass amount to be taxed by later methods
benefit_amount_to_tax = self.calculate_unclaimed_taxable_benefit(payroll_period)
# flexi's excluded from monthly tax, add flexis in this slip to total_taxable_benefit
benefit_amount_to_tax += self.get_taxable_earnings(only_flexi=True)
benefit_amount_to_tax += self.get_taxable_earnings(only_flexi=True)["taxable_earning"]
if self.deduct_tax_for_unsubmitted_tax_exemption_proof:
# calc tax to be paid for the period till date considering prorata taxes paid and proofs submitted
return self.calculate_unclaimed_taxable_earning(payroll_period, tax_component, benefit_amount_to_tax)
# calc prorata tax to be applied
return self.calculate_variable_tax(tax_component, payroll_period, benefit_amount_to_tax=benefit_amount_to_tax)
return self.calculate_variable_tax(tax_component, payroll_period, benefit_amount_to_tax)
def calculate_variable_tax(self, tax_component, payroll_period, benefit_amount_to_tax=0):
total_taxable_earning = self.get_taxable_earnings()
taxable_earnings = self.get_taxable_earnings()
period_factor = self.get_period_factor(payroll_period.start_date, payroll_period.end_date)
annual_earning = total_taxable_earning * period_factor
annual_earning = taxable_earnings["taxable_earning"] * period_factor
# Calculate total exemption declaration
exemption_amount = 0
@ -547,8 +548,8 @@ class SalarySlip(TransactionBase):
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1},
"total_exemption_amount")
annual_taxable_earning = annual_earning - exemption_amount
return self.calculate_tax(payroll_period, tax_component, annual_taxable_earning, period_factor, 0, benefit_amount_to_tax)
additional_income = benefit_amount_to_tax + taxable_earnings["additional_income"]
return self.calculate_tax(payroll_period, tax_component, annual_taxable_earning, period_factor, 0, additional_income)
def calculate_tax_for_payroll_period(self, tax_component, payroll_period):
# get total taxable income, total tax paid in payroll period
@ -570,7 +571,8 @@ class SalarySlip(TransactionBase):
total_taxable_earning = taxable_income - total_tax_exemption_proof - total_benefit_claim
# add taxable earnings of current salary_slip, include flexi
total_taxable_earning += self.get_taxable_earnings(include_flexi=1)
taxable_earnings = self.get_taxable_earnings(include_flexi=1)
total_taxable_earning += taxable_earnings["taxable_earning"] + taxable_earnings["additional_income"]
return self.calculate_tax(payroll_period, tax_component, total_taxable_earning, 1, tax_paid, 0)
def calculate_unclaimed_taxable_benefit(self, payroll_period):
@ -606,7 +608,6 @@ class SalarySlip(TransactionBase):
return total_benefit - total_benefit_claim
def calculate_unclaimed_taxable_earning(self, payroll_period, tax_component, benefit_amount_to_tax):
total_taxable_earning, total_tax_paid = 0, 0
start_date = payroll_period.start_date
# if tax deducted earlier set the start date
@ -618,19 +619,54 @@ class SalarySlip(TransactionBase):
if last_deducted and last_deducted[0][0]:
start_date = getdate(last_deducted[0][0])
total_taxable_earning, total_additional_pay = self.get_taxable_earnings_after(start_date)
total_tax_paid = self.get_tax_paid_after(start_date, payroll_period, tax_component)
total_exemption_amount = 0
# add up total Proof Submission
sum_exemption = frappe.db.sql("""select sum(total_amount) from
`tabEmployee Tax Exemption Proof Submission` where docstatus=1 and employee='{0}' and
payroll_period='{1}' and processed_in_payroll=0""".format(self.employee, payroll_period.name))
if sum_exemption and sum_exemption[0][0]:
total_exemption_amount = sum_exemption[0][0]
total_taxable_earning -= total_exemption_amount
total_additional_pay += benefit_amount_to_tax
# recalc annual tax slab by start date and end date
period_factor = self.get_period_factor(payroll_period.start_date, payroll_period.end_date, start_date, self.end_date)
annual_taxable_earning = total_taxable_earning * period_factor
return self.calculate_tax(payroll_period, tax_component, annual_taxable_earning, period_factor, total_tax_paid, total_additional_pay)
def get_taxable_earnings_after(self, start_date):
total_taxable_earning, total_additional_pay = 0, 0
# calc total taxable amount in period
sum_taxable_earning = frappe.db.sql("""select sum(sd.amount) from `tabSalary Detail` sd join
`tabSalary Slip` ss on sd.parent=ss.name where sd.parentfield='earnings'
and sd.is_tax_applicable=1 and is_flexible_benefit=0 and ss.docstatus=1
and ss.employee='{0}' and ss.start_date between '{1}' and '{2}' and
ss.end_date between '{1}' and '{2}'""".format(self.employee,
and sd.is_tax_applicable=1 and is_additional_component=0 and is_flexible_benefit=0
and ss.docstatus=1 and ss.employee='{0}' and ss.start_date between '{1}' and '{2}'
and ss.end_date between '{1}' and '{2}'""".format(self.employee,
start_date, self.start_date))
if sum_taxable_earning and sum_taxable_earning[0][0]:
total_taxable_earning = sum_taxable_earning[0][0]
# add taxable earning in this salary slip
total_taxable_earning += self.get_taxable_earnings()
sum_additional_earning = frappe.db.sql("""select sum(sd.amount) from `tabSalary Detail` sd join
`tabSalary Slip` ss on sd.parent=ss.name where sd.parentfield='earnings'
and sd.is_tax_applicable=1 and is_additional_component=1 and is_flexible_benefit=0
and ss.docstatus=1 and ss.employee='{0}' and ss.start_date between '{1}' and '{2}'
and ss.end_date between '{1}' and '{2}'""".format(self.employee,
start_date, self.start_date))
if sum_additional_earning and sum_additional_earning[0][0]:
total_additional_pay = sum_additional_earning[0][0]
# add taxable earning, additional_income in this salary slip
taxable_earnings = self.get_taxable_earnings()
total_taxable_earning += taxable_earnings["taxable_earning"]
total_additional_pay += taxable_earnings["additional_income"]
return total_taxable_earning, total_additional_pay
def get_tax_paid_after(self, start_date, payroll_period, tax_component):
total_tax_paid = 0
# find total_tax_paid from salary slip where benefit is not taxed
sum_tax_paid = frappe.db.sql("""select sum(sd.amount) from `tabSalary Detail` sd join
`tabSalary Slip` ss on sd.parent=ss.name where sd.parentfield='deductions'
@ -654,49 +690,42 @@ class SalarySlip(TransactionBase):
struct_row, pro_rata_tax = ss_obj.calculate_variable_tax(tax_component, payroll_period)
if pro_rata_tax:
total_tax_paid += pro_rata_tax
total_exemption_amount = 0
# add up total Proof Submission
sum_exemption = frappe.db.sql("""select sum(total_amount) from
`tabEmployee Tax Exemption Proof Submission` where docstatus=1 and employee='{0}' and
payroll_period='{1}' and processed_in_payroll=0""".format(self.employee, payroll_period.name))
if sum_exemption and sum_exemption[0][0]:
total_exemption_amount = sum_exemption[0][0]
total_taxable_earning -= total_exemption_amount
# recalc annual tax slab by start date and end date
period_factor = self.get_period_factor(payroll_period.start_date, payroll_period.end_date, start_date, self.end_date)
annual_taxable_earning = total_taxable_earning * period_factor
return self.calculate_tax(payroll_period, tax_component, annual_taxable_earning, period_factor, total_tax_paid, benefit_amount_to_tax)
return total_tax_paid
def get_taxable_earnings(self, include_flexi=0, only_flexi=0):
taxable_earning = 0
additional_income = 0
for earning in self.earnings:
if only_flexi:
if earning.is_tax_applicable and earning.is_flexible_benefit:
taxable_earning += earning.amount
continue
if include_flexi:
if earning.is_tax_applicable or (earning.is_tax_applicable and earning.is_flexible_benefit):
taxable_earning += earning.amount
else:
if earning.is_tax_applicable and not earning.is_flexible_benefit:
taxable_earning += earning.amount
return taxable_earning
if earning.is_tax_applicable:
if earning.is_additional_component:
additional_income += earning.amount
continue
if only_flexi:
if earning.is_tax_applicable and earning.is_flexible_benefit:
taxable_earning += earning.amount
continue
if include_flexi:
if earning.is_tax_applicable or (earning.is_tax_applicable and earning.is_flexible_benefit):
taxable_earning += earning.amount
else:
if earning.is_tax_applicable and not earning.is_flexible_benefit:
taxable_earning += earning.amount
return {"taxable_earning": taxable_earning, "additional_income": additional_income}
def calculate_tax(self, payroll_period, tax_component, annual_taxable_earning, period_factor, tax_paid=0, benefit_amount_to_tax=0):
def calculate_tax(self, payroll_period, tax_component, annual_taxable_earning, period_factor, tax_paid=0, additional_income=0):
# Get tax calc by period
annual_tax = self.calculate_tax_by_tax_slab(payroll_period.name, annual_taxable_earning)
# Calc prorata tax
tax_amount = annual_tax / period_factor
# find the annual tax diff caused by additional_income, add to tax_amount
if additional_income > 0:
annual_tax_with_additional_income = self.calculate_tax_by_tax_slab(payroll_period.name, annual_taxable_earning + additional_income)
tax_amount += annual_tax_with_additional_income - annual_tax
#less paid taxes
if tax_paid:
tax_amount -= tax_paid
# find the annual tax diff caused by benefit_amount_to_tax, add to tax_amount
if benefit_amount_to_tax > 0:
annual_tax_with_benefit_amt = self.calculate_tax_by_tax_slab(payroll_period.name, annual_taxable_earning + benefit_amount_to_tax)
tax_amount += annual_tax_with_benefit_amt - annual_tax
struct_row = self.get_salary_slip_row(tax_component)
return struct_row, tax_amount

View File

@ -14,7 +14,7 @@ def execute(filters=None):
qty_to_make = filters.get("qty_to_make")
for rows in data:
item_map = get_item_details(rows[0])
item_map = get_item_details(rows[0])
reqd_qty = qty_to_make * rows[3]
last_pur_price = frappe.db.get_value("Item", rows[0], "last_purchase_rate")
if rows[4] > 0:
@ -79,7 +79,7 @@ def get_bom_stock(filters):
LEFT JOIN `tabBin` AS ledger
ON bom_item.item_code = ledger.item_code
{conditions}
WHERE
bom_item.parent = '{bom}' and bom_item.parenttype='BOM'
@ -89,5 +89,3 @@ def get_item_details(item_code):
items = frappe.db.sql("""select it.item_group, it.item_name, it.stock_uom, it.name, it.brand, it.description, it.manufacturer_part_no, it.manufacturer from tabItem it where it.item_code = %s""", item_code, as_dict=1)
return dict((d.name, d) for d in items)