Merge pull request #14108 from ESS-LLP/tax_deduction

Variable tax deduction
This commit is contained in:
rohitwaghchaure 2018-05-17 13:55:52 +05:30 committed by GitHub
commit 4444430200
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 223 additions and 12 deletions

View File

@ -139,6 +139,37 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_exemption_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Exemption Amount",
"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_on_submit": 0,
@ -243,7 +274,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-05-15 16:16:46.075493",
"modified": "2018-05-16 19:03:57.624215",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee Tax Exemption Declaration",

View File

@ -19,3 +19,6 @@ class EmployeeTaxExemptionDeclaration(Document):
"docstatus": 1}):
frappe.throw(_("Tax Declaration of {0} for period {1} already submitted.")\
.format(self.employee, self.payroll_period), frappe.DocstatusTransitionError)
self.total_exemption_amount = 0
for item in self.declarations:
self.total_exemption_amount += item.amount

View File

@ -18,4 +18,13 @@ class SalaryComponent(Document):
self.salary_component_abbr = self.salary_component_abbr.strip()
self.salary_component_abbr = append_number_if_name_exists('Salary Component', self.salary_component_abbr,
'salary_component_abbr', separator='_', filters={"name": ["!=", self.name]})
'salary_component_abbr', separator='_', filters={"name": ["!=", self.name]})
def calculate_tax(self, annual_earning):
taxable_amount = 0
for slab in self.taxable_salary_slabs:
if annual_earning > slab.from_amount and annual_earning < slab.to_amount:
taxable_amount += (annual_earning - slab.from_amount) * slab.percent_deduction *.01
elif annual_earning > slab.from_amount and annual_earning > slab.to_amount:
taxable_amount += (slab.to_amount - slab.from_amount) * slab.percent_deduction * .01
return taxable_amount

View File

@ -40,6 +40,7 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -72,6 +73,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -101,6 +103,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -132,6 +135,100 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_tax_applicable",
"fieldtype": "Check",
"hidden": 0,
"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 Tax Applicable",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "is_flexible_benefit",
"fieldtype": "Check",
"hidden": 0,
"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 Flexible Benefit",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"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_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "variable_based_on_taxable_salary",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Variable Based On Taxable Salary",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -161,6 +258,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -192,6 +290,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -225,6 +324,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -258,6 +358,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -290,6 +391,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -321,6 +423,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -351,6 +454,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -383,6 +487,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -413,6 +518,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
@ -445,6 +551,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -458,7 +565,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2017-10-02 13:57:22.769751",
"modified": "2018-05-16 22:42:59.974450",
"modified_by": "Administrator",
"module": "HR",
"name": "Salary Detail",

View File

@ -13,6 +13,7 @@ from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
from erpnext.utilities.transaction_base import TransactionBase
from frappe.utils.background_jobs import enqueue
from erpnext.hr.doctype.additional_salary_component.additional_salary_component import get_additional_salary_component
from erpnext.hr.utils import get_payroll_period
class SalarySlip(TransactionBase):
def autoname(self):
@ -58,6 +59,10 @@ class SalarySlip(TransactionBase):
amount = self.eval_condition_and_formula(struct_row, data)
if amount and struct_row.statistical_component == 0:
self.update_component_row(struct_row, amount, key)
if key=="deductions" and struct_row.variable_based_on_taxable_salary:
tax_row, amount = self.calculate_pro_rata_tax(struct_row.salary_component)
if tax_row and amount:
self.update_component_row(frappe._dict(tax_row), amount, key)
additional_components = get_additional_salary_component(self.employee, self.start_date, self.end_date)
if additional_components:
@ -464,6 +469,52 @@ class SalarySlip(TransactionBase):
status = "Cancelled"
return status
def calculate_pro_rata_tax(self, salary_component):
# Calculate total tax payable earnings
tax_applicable_components = []
for earning in self._salary_structure_doc.earnings:
#all tax applicable earnings which are not flexi
if earning.is_tax_applicable and not earning.is_flexible_benefit:
tax_applicable_components.append(earning.salary_component)
total_taxable_earning = 0
for earning in self.earnings:
if earning.salary_component in tax_applicable_components:
total_taxable_earning += earning.amount
# Get payroll period, prorata frequency
days = date_diff(self.end_date, self.start_date) + 1
payroll_period = get_payroll_period(self.start_date, self.end_date, self.company)
if not payroll_period:
frappe.throw(_("Start and end dates not in a valid Payroll Period"))
total_days = date_diff(payroll_period.end_date, payroll_period.start_date) + 1
prorata_frequency = flt(total_days)/flt(days)
annual_earning = total_taxable_earning * prorata_frequency
# Calculate total exemption declaration
exemption_amount = 0
if frappe.db.exists("Employee Tax Exemption Declaration", {"employee": self.employee,
"payroll_period": payroll_period.name, "docstatus": 1}):
exemption_amount = frappe.db.get_value("Employee Tax Exemption Declaration",
{"employee": self.employee, "payroll_period": payroll_period.name, "docstatus": 1}, #fix period
"total_exemption_amount")
annual_earning = annual_earning - exemption_amount
# Get tax calc by component
component = frappe.get_doc("Salary Component", salary_component)
annual_tax = component.calculate_tax(annual_earning)
# Calc prorata tax
pro_rata_tax = annual_tax/prorata_frequency
# Data for update_component_row
struct_row = {}
struct_row['depends_on_lwp'] = 0
struct_row['salary_component'] = component.name
struct_row['abbr'] = component.salary_component_abbr
struct_row['do_not_include_in_total'] = 0
return struct_row, pro_rata_tax
def unlink_ref_doc_from_salary_slip(ref_no):
linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip`
where journal_entry=%s and docstatus < 2""", (ref_no))

View File

@ -201,17 +201,20 @@ frappe.ui.form.on('Salary Detail', {
callback: function(data) {
if(data.message){
var result = data.message;
frappe.model.set_value(cdt, cdn, 'condition',result.condition);
frappe.model.set_value(cdt, cdn, 'amount_based_on_formula',result.amount_based_on_formula);
frappe.model.set_value(cdt, cdn, 'condition', result.condition);
frappe.model.set_value(cdt, cdn, 'amount_based_on_formula', result.amount_based_on_formula);
if(result.amount_based_on_formula == 1){
frappe.model.set_value(cdt, cdn, 'formula',result.formula);
frappe.model.set_value(cdt, cdn, 'formula', result.formula);
}
else{
frappe.model.set_value(cdt, cdn, 'amount',result.amount);
frappe.model.set_value(cdt, cdn, 'amount', result.amount);
}
frappe.model.set_value(cdt, cdn, 'statistical_component',result.statistical_component);
frappe.model.set_value(cdt, cdn, 'depends_on_lwp',result.depends_on_lwp);
frappe.model.set_value(cdt, cdn, 'do_not_include_in_total',result.do_not_include_in_total);
frappe.model.set_value(cdt, cdn, 'statistical_component', result.statistical_component);
frappe.model.set_value(cdt, cdn, 'depends_on_lwp', result.depends_on_lwp);
frappe.model.set_value(cdt, cdn, 'do_not_include_in_total', result.do_not_include_in_total);
frappe.model.set_value(cdt, cdn, 'variable_based_on_taxable_salary', result.variable_based_on_taxable_salary);
frappe.model.set_value(cdt, cdn, 'is_tax_applicable', result.is_tax_applicable);
frappe.model.set_value(cdt, cdn, 'is_flexible_benefit', result.is_flexible_benefit);
refresh_field("earnings");
refresh_field("deductions");
}

View File

@ -50,7 +50,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "to_amount",
"fieldtype": "Data",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -147,7 +147,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2018-04-13 20:09:36.675987",
"modified": "2018-05-16 18:18:23.802576",
"modified_by": "Administrator",
"module": "HR",
"name": "Taxable Salary Slab",

View File

@ -234,3 +234,10 @@ def get_leave_period(from_date, to_date, company):
if leave_period:
return leave_period
def get_payroll_period(from_date, to_date, company):
payroll_period = frappe.db.sql("""select pp.name, pd.start_date, pd.end_date from
`tabPayroll Period Date` pd join `tabPayroll Period` pp on
pd.parent=pp.name where pd.start_date<=%s and pd.end_date>= %s
and pp.company=%s""", (from_date, to_date, company), as_dict=1)
return payroll_period[0] if payroll_period else None