From 04f48a011d343cad2dbe667b68408db6d523982e Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 01:31:00 +0530 Subject: [PATCH 01/13] feat: Add year_to_date field --- erpnext/payroll/doctype/salary_slip/salary_slip.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index 386618cf08..b64e5a08fe 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -69,6 +69,7 @@ "net_pay_info", "net_pay", "base_net_pay", + "year_to_date", "column_break_53", "rounded_total", "base_rounded_total", @@ -578,13 +579,18 @@ { "fieldname": "column_break_69", "fieldtype": "Column Break" + }, + { + "fieldname": "year_to_date", + "fieldtype": "Currency", + "label": "Year To Date" } ], "icon": "fa fa-file-text", "idx": 9, "is_submittable": 1, "links": [], - "modified": "2020-10-21 23:02:59.400249", + "modified": "2020-12-17 21:51:19.612940", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", From 9f1e018e4f868220a985af6784c1940a67d47b82 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 01:35:27 +0530 Subject: [PATCH 02/13] feat: Compute year_to_date --- .../doctype/salary_slip/salary_slip.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 20365b191d..27de46acc3 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -35,6 +35,9 @@ class SalarySlip(TransactionBase): def autoname(self): self.name = make_autoname(self.series) + def before_save(self): + self.compute_year_to_date() + def validate(self): self.status = self.get_status() self.validate_dates() @@ -1125,6 +1128,26 @@ class SalarySlip(TransactionBase): self.gross_pay += self.earnings[i].amount self.net_pay = flt(self.gross_pay) - flt(self.total_deduction) + def compute_year_to_date(self): + year_to_date = 0 + fiscal_year = frappe.get_list('Fiscal Year', + fields = ['year','year_start_date','year_end_date'], + filters= {'year_start_date' : ['<=', self.start_date], + 'year_end_date' : ['>=', self.end_date] + })[0] + salary_slips_from_current_fiscal_year = frappe.get_list('Salary Slip', + fields = ['employee_name', 'start_date', 'end_date', 'net_pay'], + filters = {'employee_name' : self.employee_name, + 'start_date' : ['>=', fiscal_year.year_start_date], + 'end_date' : ['<=', fiscal_year.year_end_date] + }) + + for salary_slip in salary_slips_from_current_fiscal_year: + year_to_date += salary_slip.net_pay + + year_to_date += self.net_pay + self.year_to_date = year_to_date + 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)) @@ -1135,4 +1158,4 @@ def unlink_ref_doc_from_salary_slip(ref_no): def generate_password_for_pdf(policy_template, employee): employee = frappe.get_doc("Employee", employee) - return policy_template.format(**employee.as_dict()) + return policy_template.format(**employee.as_dict()) \ No newline at end of file From 89a02d7d3f705742bc95e654e2909a821e883e45 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 14:59:20 +0530 Subject: [PATCH 03/13] feat: Changed Fiscal Year to Payroll Period --- .../doctype/salary_slip/salary_slip.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 27de46acc3..0ea0684a8f 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -35,9 +35,6 @@ class SalarySlip(TransactionBase): def autoname(self): self.name = make_autoname(self.series) - def before_save(self): - self.compute_year_to_date() - def validate(self): self.status = self.get_status() self.validate_dates() @@ -52,6 +49,7 @@ class SalarySlip(TransactionBase): self.get_working_days_details(lwp = self.leave_without_pay) self.calculate_net_pay() + self.compute_year_to_date() if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"): max_working_hours = frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet") @@ -1130,19 +1128,21 @@ class SalarySlip(TransactionBase): def compute_year_to_date(self): year_to_date = 0 - fiscal_year = frappe.get_list('Fiscal Year', - fields = ['year','year_start_date','year_end_date'], - filters= {'year_start_date' : ['<=', self.start_date], - 'year_end_date' : ['>=', self.end_date] + payroll_period = frappe.get_list('Payroll Period', + fields = ['start_date','end_date','company'], + filters= {'start_date' : ['<=', self.start_date], + 'end_date' : ['>=', self.end_date], + 'company' : self.company })[0] - salary_slips_from_current_fiscal_year = frappe.get_list('Salary Slip', + salary_slips_from_current_payroll_period = frappe.get_list('Salary Slip', fields = ['employee_name', 'start_date', 'end_date', 'net_pay'], filters = {'employee_name' : self.employee_name, - 'start_date' : ['>=', fiscal_year.year_start_date], - 'end_date' : ['<=', fiscal_year.year_end_date] + 'start_date' : ['>=', payroll_period.start_date], + 'end_date' : ['<=', payroll_period.end_date], + 'name' : ['!=', self.name] }) - for salary_slip in salary_slips_from_current_fiscal_year: + for salary_slip in salary_slips_from_current_payroll_period: year_to_date += salary_slip.net_pay year_to_date += self.net_pay From 1b1df6b6bcabedcf27ebc5c1cc4f2c0fac1e73b8 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 23:51:05 +0530 Subject: [PATCH 04/13] feat: Add month_to_date field --- erpnext/payroll/doctype/salary_slip/salary_slip.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index b64e5a08fe..5141868adb 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -73,6 +73,7 @@ "column_break_53", "rounded_total", "base_rounded_total", + "month_to_date", "section_break_55", "total_in_words", "column_break_69", @@ -583,14 +584,21 @@ { "fieldname": "year_to_date", "fieldtype": "Currency", - "label": "Year To Date" + "label": "Year To Date(Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 + }, + { + "fieldname": "month_to_date", + "fieldtype": "Currency", + "label": "Month To Date" } ], "icon": "fa fa-file-text", "idx": 9, "is_submittable": 1, "links": [], - "modified": "2020-12-17 21:51:19.612940", + "modified": "2020-12-18 23:23:10.484574", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", From 59fbf702dad1c4231d19fe8cfb4970862e4aaad0 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 23:52:11 +0530 Subject: [PATCH 05/13] feat: Compute month_to_date --- .../doctype/salary_slip/salary_slip.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 0ea0684a8f..e86a7fc315 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -50,6 +50,7 @@ class SalarySlip(TransactionBase): self.calculate_net_pay() self.compute_year_to_date() + self.compute_month_to_date() if frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet"): max_working_hours = frappe.db.get_single_value("Payroll Settings", "max_working_hours_against_timesheet") @@ -1138,8 +1139,7 @@ class SalarySlip(TransactionBase): fields = ['employee_name', 'start_date', 'end_date', 'net_pay'], filters = {'employee_name' : self.employee_name, 'start_date' : ['>=', payroll_period.start_date], - 'end_date' : ['<=', payroll_period.end_date], - 'name' : ['!=', self.name] + 'end_date' : ['<', self.start_date] }) for salary_slip in salary_slips_from_current_payroll_period: @@ -1148,6 +1148,22 @@ class SalarySlip(TransactionBase): year_to_date += self.net_pay self.year_to_date = year_to_date + def compute_month_to_date(self): + month_to_date = 0 + date = datetime.datetime.strptime(self.start_date,"%Y-%m-%d") + first_day_of_the_month = "1-" + str(date.month) + "-" + str(date.year) + salary_slips_from_this_month = frappe.get_list('Salary Slip', + fields = ['employee_name', 'start_date', 'net_pay'], + filters = {'employee_name' : self.employee_name, + 'start_date' : ['>=', first_day_of_the_month], + 'end_date' : ['<', self.start_date] + }) + for salary_slip in salary_slips_from_this_month: + month_to_date += salary_slip.net_pay + + month_to_date += self.net_pay + self.month_to_date = month_to_date + 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)) From ddd9fe49fca4f05f31bc97e462a478aa52477e2d Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Fri, 18 Dec 2020 23:58:05 +0530 Subject: [PATCH 06/13] feat: Add month_to_date field --- erpnext/payroll/doctype/salary_slip/salary_slip.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index 5141868adb..d981a39953 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -591,14 +591,16 @@ { "fieldname": "month_to_date", "fieldtype": "Currency", - "label": "Month To Date" + "label": "Month To Date(Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 } ], "icon": "fa fa-file-text", "idx": 9, "is_submittable": 1, "links": [], - "modified": "2020-12-18 23:23:10.484574", + "modified": "2020-12-18 23:57:41.042954", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", From c36cab81f229376cbdde96cf7cfe4ccbd33b6f36 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Mon, 21 Dec 2020 23:46:02 +0530 Subject: [PATCH 07/13] fix: Update year_to_date and month_to_date field labels to show company currency --- .../doctype/salary_slip/salary_slip.js | 6 +++--- .../doctype/salary_slip/salary_slip.json | 20 +++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.js b/erpnext/payroll/doctype/salary_slip/salary_slip.js index f7e22c6387..5694871762 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.js +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.js @@ -125,15 +125,15 @@ frappe.ui.form.on("Salary Slip", { change_form_labels: function(frm, company_currency) { frm.set_currency_labels(["base_hour_rate", "base_gross_pay", "base_total_deduction", - "base_net_pay", "base_rounded_total", "base_total_in_words"], + "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"], company_currency); - frm.set_currency_labels(["hour_rate", "gross_pay", "total_deduction", "net_pay", "rounded_total", "total_in_words"], + frm.set_currency_labels(["hour_rate", "gross_pay", "total_deduction", "net_pay", "rounded_total", "total_in_words", "year_to_date", "month_to_date"], frm.doc.currency); // toggle fields frm.toggle_display(["exchange_rate", "base_hour_rate", "base_gross_pay", "base_total_deduction", - "base_net_pay", "base_rounded_total", "base_total_in_words"], + "base_net_pay", "base_rounded_total", "base_total_in_words", "base_year_to_date", "base_month_to_date"], frm.doc.currency != company_currency); }, diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.json b/erpnext/payroll/doctype/salary_slip/salary_slip.json index d981a39953..43deee43aa 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.json +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.json @@ -70,10 +70,12 @@ "net_pay", "base_net_pay", "year_to_date", + "base_year_to_date", "column_break_53", "rounded_total", "base_rounded_total", "month_to_date", + "base_month_to_date", "section_break_55", "total_in_words", "column_break_69", @@ -584,12 +586,26 @@ { "fieldname": "year_to_date", "fieldtype": "Currency", + "label": "Year To Date", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "month_to_date", + "fieldtype": "Currency", + "label": "Month To Date", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "base_year_to_date", + "fieldtype": "Currency", "label": "Year To Date(Company Currency)", "options": "Company:company:default_currency", "read_only": 1 }, { - "fieldname": "month_to_date", + "fieldname": "base_month_to_date", "fieldtype": "Currency", "label": "Month To Date(Company Currency)", "options": "Company:company:default_currency", @@ -600,7 +616,7 @@ "idx": 9, "is_submittable": 1, "links": [], - "modified": "2020-12-18 23:57:41.042954", + "modified": "2020-12-21 23:43:44.959840", "modified_by": "Administrator", "module": "Payroll", "name": "Salary Slip", From 090783804bdc59f22b8a7afee43cb3ddabcd37b2 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Mon, 21 Dec 2020 23:52:05 +0530 Subject: [PATCH 08/13] fix: Improve month_to_date computation --- erpnext/payroll/doctype/salary_slip/salary_slip.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index e86a7fc315..02e5f2d1d1 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe, erpnext import datetime, math -from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate +from frappe.utils import add_days, cint, cstr, flt, getdate, rounded, date_diff, money_in_words, formatdate, get_first_day from frappe.model.naming import make_autoname from frappe import msgprint, _ @@ -1150,8 +1150,7 @@ class SalarySlip(TransactionBase): def compute_month_to_date(self): month_to_date = 0 - date = datetime.datetime.strptime(self.start_date,"%Y-%m-%d") - first_day_of_the_month = "1-" + str(date.month) + "-" + str(date.year) + first_day_of_the_month = get_first_day(self.start_date) salary_slips_from_this_month = frappe.get_list('Salary Slip', fields = ['employee_name', 'start_date', 'net_pay'], filters = {'employee_name' : self.employee_name, From 353f8f4d857381baf0bfa8e4b50e698b49f59da9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 29 Dec 2020 22:13:40 +0530 Subject: [PATCH 09/13] fix: Add test case for YTD --- ...test_employee_tax_exemption_declaration.py | 16 ++-- .../doctype/salary_slip/salary_slip.py | 49 ++++++------ .../doctype/salary_slip/test_salary_slip.py | 76 ++++++++++++++----- .../salary_structure/test_salary_structure.py | 18 +++-- 4 files changed, 106 insertions(+), 53 deletions(-) diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py index 0609d19149..311f3527f6 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py @@ -86,19 +86,21 @@ class TestEmployeeTaxExemptionDeclaration(unittest.TestCase): self.assertEqual(declaration.total_exemption_amount, 100000) -def create_payroll_period(): - if not frappe.db.exists("Payroll Period", "_Test Payroll Period"): +def create_payroll_period(**args): + args = frappe._dict(args) + name = args.name or "_Test Payroll Period" + if not frappe.db.exists("Payroll Period", name): from datetime import date payroll_period = frappe.get_doc(dict( doctype = 'Payroll Period', - name = "_Test Payroll Period", - company = erpnext.get_default_company(), - start_date = date(date.today().year, 1, 1), - end_date = date(date.today().year, 12, 31) + name = name, + company = args.company or erpnext.get_default_company(), + start_date = args.start_date or date(date.today().year, 1, 1), + end_date = args.end_date or date(date.today().year, 12, 31) )).insert() return payroll_period else: - return frappe.get_doc("Payroll Period", "_Test Payroll Period") + return frappe.get_doc("Payroll Period", name) def create_exemption_category(): if not frappe.db.exists("Employee Tax Exemption Category", "_Test Category"): diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 02e5f2d1d1..9f46d50e58 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -18,6 +18,7 @@ from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_fac from erpnext.payroll.doctype.employee_benefit_application.employee_benefit_application import get_benefit_component_amount from erpnext.payroll.doctype.employee_benefit_claim.employee_benefit_claim import get_benefit_claim_amount, get_last_payroll_period_benefits from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts, create_repayment_entry +from erpnext.accounts.utils import get_fiscal_year class SalarySlip(TransactionBase): def __init__(self, *args, **kwargs): @@ -1129,21 +1130,25 @@ class SalarySlip(TransactionBase): def compute_year_to_date(self): year_to_date = 0 - payroll_period = frappe.get_list('Payroll Period', - fields = ['start_date','end_date','company'], - filters= {'start_date' : ['<=', self.start_date], - 'end_date' : ['>=', self.end_date], - 'company' : self.company - })[0] - salary_slips_from_current_payroll_period = frappe.get_list('Salary Slip', - fields = ['employee_name', 'start_date', 'end_date', 'net_pay'], - filters = {'employee_name' : self.employee_name, - 'start_date' : ['>=', payroll_period.start_date], - 'end_date' : ['<', self.start_date] - }) + payroll_period = get_payroll_period(self.start_date, self.end_date, self.company) - for salary_slip in salary_slips_from_current_payroll_period: - year_to_date += salary_slip.net_pay + if payroll_period: + period_start_date = payroll_period.start_date + period_end_date = payroll_period.end_date + else: + # get dates based on fiscal year if no payroll period exists + fiscal_year = get_fiscal_year(date=self.start_date, company=self.company, as_dict=1) + period_start_date = fiscal_year.year_start_date + period_end_date = fiscal_year.year_end_date + + salary_slip_sum = frappe.get_list('Salary Slip', + fields = ['sum(net_pay) as sum'], + filters = {'employee_name' : self.employee_name, + 'start_date' : ['>=', period_start_date], + 'end_date' : ['<', period_end_date]}) + + + year_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0 year_to_date += self.net_pay self.year_to_date = year_to_date @@ -1151,14 +1156,14 @@ class SalarySlip(TransactionBase): def compute_month_to_date(self): month_to_date = 0 first_day_of_the_month = get_first_day(self.start_date) - salary_slips_from_this_month = frappe.get_list('Salary Slip', - fields = ['employee_name', 'start_date', 'net_pay'], - filters = {'employee_name' : self.employee_name, - 'start_date' : ['>=', first_day_of_the_month], - 'end_date' : ['<', self.start_date] - }) - for salary_slip in salary_slips_from_this_month: - month_to_date += salary_slip.net_pay + salary_slip_sum = frappe.get_list('Salary Slip', + fields = ['sum(net_pay) as sum'], + filters = {'employee_name' : self.employee_name, + 'start_date' : ['>=', first_day_of_the_month], + 'end_date' : ['<', self.start_date] + }) + + year_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0 month_to_date += self.net_pay self.month_to_date = month_to_date diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 5daf1d439d..687d3602a9 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -290,6 +290,35 @@ class TestSalarySlip(unittest.TestCase): self.assertEqual(salary_slip.gross_pay, 78000) self.assertEqual(salary_slip.base_gross_pay, 78000*70) + def test_year_to_date_computation(self): + from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + + applicant = make_employee("test_ytd@salary.com", company="_Test Company") + + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company", + start_date=getdate("2019-04-01"), end_date=getdate("2020-03-31")) + + create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01")) + + salary_structure = make_salary_structure("Monthly Salary Structure Test for Salary Slip YTD", + "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period) + + # clear salary slip for this employee + frappe.db.sql("DELETE FROM `tabSalary Slip` where employee_name = 'test_ytd@salary.com'") + + create_salary_slips_for_payroll_period(applicant, salary_structure.name, + payroll_period, deduct_random=False) + + salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date'], filters={'employee_name': + 'test_ytd@salary.com'}, order_by = 'posting_date') + + net_pay = 70026.00 + month = 1 + for slip in salary_slips: + year_to_date = month * net_pay + self.assertEqual(slip.year_to_date, year_to_date) + month += 1 + def test_tax_for_payroll_period(self): data = {} # test the impact of tax exemption declaration, tax exemption proof submission @@ -631,8 +660,13 @@ def create_benefit_claim(employee, payroll_period, amount, component): }).submit() return claim_date -def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=erpnext.get_default_currency()): - frappe.db.sql("""delete from `tabIncome Tax Slab`""") +def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=None): + # frappe.db.sql("""delete from `tabIncome Tax Slab`""") + + print(payroll_period.name, effective_date) + + if not currency: + currency = erpnext.get_default_currency() slabs = [ { @@ -652,26 +686,32 @@ def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = } ] - income_tax_slab = frappe.new_doc("Income Tax Slab") - income_tax_slab.name = "Tax Slab: " + payroll_period.name - income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2) - income_tax_slab.currency = currency + income_tax_slab_name = frappe.db.get_value("Income Tax Slab", "Tax Slab: " + payroll_period.name) + if not income_tax_slab_name: + income_tax_slab = frappe.new_doc("Income Tax Slab") + income_tax_slab.name = "Tax Slab: " + payroll_period.name + income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2) + income_tax_slab.currency = currency - if allow_tax_exemption: - income_tax_slab.allow_tax_exemption = 1 - income_tax_slab.standard_tax_exemption_amount = 50000 + if allow_tax_exemption: + income_tax_slab.allow_tax_exemption = 1 + income_tax_slab.standard_tax_exemption_amount = 50000 - for item in slabs: - income_tax_slab.append("slabs", item) + for item in slabs: + income_tax_slab.append("slabs", item) - income_tax_slab.append("other_taxes_and_charges", { - "description": "cess", - "percent": 4 - }) + income_tax_slab.append("other_taxes_and_charges", { + "description": "cess", + "percent": 4 + }) - income_tax_slab.save() - if not dont_submit: - income_tax_slab.submit() + income_tax_slab.save() + if not dont_submit: + income_tax_slab.submit() + + return income_tax_slab.name + else: + return income_tax_slab_name def create_salary_slips_for_payroll_period(employee, salary_structure, payroll_period, deduct_random=True): deducted_dates = [] diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index abb669740b..e1c6a008aa 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -114,7 +114,7 @@ class TestSalaryStructure(unittest.TestCase): self.assertEqual(sal_struct.currency, 'USD') def make_salary_structure(salary_structure, payroll_frequency, employee=None, dont_submit=False, other_details=None, - test_tax=False, company=None, currency=erpnext.get_default_currency()): + test_tax=False, company=None, currency=erpnext.get_default_currency(), payroll_period=None): if test_tax: frappe.db.sql("""delete from `tabSalary Structure` where name=%s""",(salary_structure)) @@ -141,16 +141,22 @@ def make_salary_structure(salary_structure, payroll_frequency, employee=None, do if employee and not frappe.db.get_value("Salary Structure Assignment", {'employee':employee, 'docstatus': 1}) and salary_structure_doc.docstatus==1: - create_salary_structure_assignment(employee, salary_structure, company=company, currency=currency) + create_salary_structure_assignment(employee, salary_structure, company=company, currency=currency, + payroll_period=payroll_period) return salary_structure_doc -def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None, currency=erpnext.get_default_currency()): +def create_salary_structure_assignment(employee, salary_structure, from_date=None, company=None, currency=erpnext.get_default_currency(), + payroll_period=None): + if frappe.db.exists("Salary Structure Assignment", {"employee": employee}): frappe.db.sql("""delete from `tabSalary Structure Assignment` where employee=%s""",(employee)) - payroll_period = create_payroll_period() - create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) + if not payroll_period: + payroll_period = create_payroll_period() + income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) + else: + income_tax_slab = frappe.db.get_value('Income Tax Slab', "Tax Slab: " + payroll_period.name) salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") salary_structure_assignment.employee = employee @@ -162,7 +168,7 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non salary_structure_assignment.payroll_payable_account = get_payable_account(company) salary_structure_assignment.company = company or erpnext.get_default_company() salary_structure_assignment.save(ignore_permissions=True) - salary_structure_assignment.income_tax_slab = "Tax Slab: _Test Payroll Period" + salary_structure_assignment.income_tax_slab = income_tax_slab salary_structure_assignment.submit() return salary_structure_assignment From 20133bd1dfc7fa983e78af18ea827bfee7c2e86d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 29 Dec 2020 22:19:12 +0530 Subject: [PATCH 10/13] fix: Remove comments --- erpnext/payroll/doctype/salary_slip/test_salary_slip.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 687d3602a9..d1eaae7490 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -661,10 +661,6 @@ def create_benefit_claim(employee, payroll_period, amount, component): return claim_date def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=None): - # frappe.db.sql("""delete from `tabIncome Tax Slab`""") - - print(payroll_period.name, effective_date) - if not currency: currency = erpnext.get_default_currency() From 8b7ebe5044b823ccad309f9cd241bd335af93cba Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 30 Dec 2020 12:45:46 +0530 Subject: [PATCH 11/13] fix: Test Case cleanup and fixes --- .../loan_management/doctype/loan/test_loan.py | 2 +- .../income_tax_slab/income_tax_slab.py | 7 +++-- .../doctype/salary_slip/test_salary_slip.py | 30 +++++++++++-------- .../salary_structure/test_salary_structure.py | 5 ++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index a63d06590f..1d831aeb64 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -45,7 +45,7 @@ class TestLoan(unittest.TestCase): create_loan_security_price("Test Security 2", 250, "Nos", get_datetime() , get_datetime(add_to_date(nowdate(), hours=24))) self.applicant1 = make_employee("robert_loan@loan.com") - make_salary_structure("Test Salary Structure Loan", "Monthly", employee=self.applicant1, currency='INR') + make_salary_structure("Test Salary Structure Loan", "Monthly", employee=self.applicant1, currency='INR', company="_Test Company") if not frappe.db.exists("Customer", "_Test Loan Customer"): frappe.get_doc(get_customer_dict('_Test Loan Customer')).insert(ignore_permissions=True) diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py index 253f023f68..e2b22a6ce9 100644 --- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py +++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py @@ -3,8 +3,11 @@ # For license information, please see license.txt from __future__ import unicode_literals -# import frappe +import frappe +import erpnext from frappe.model.document import Document class IncomeTaxSlab(Document): - pass + def validate(self): + if self.company: + self.currency = erpnext.get_company_currency(self.company) diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index d1eaae7490..9e3e707f39 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -240,7 +240,12 @@ class TestSalarySlip(unittest.TestCase): interest_income_account='Interest Income Account - _TC', penalty_income_account='Penalty Income Account - _TC') - make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR') + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company", + start_date=getdate("2019-04-01"), end_date=getdate("2020-03-31")) + + make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR', + payroll_period=payroll_period) + frappe.db.sql("""delete from `tabLoan""") loan = create_loan(applicant, "Car Loan", 11000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1)) loan.repay_from_salary = 1 @@ -298,7 +303,8 @@ class TestSalarySlip(unittest.TestCase): payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company", start_date=getdate("2019-04-01"), end_date=getdate("2020-03-31")) - create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01")) + create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01"), + company="_Test Company") salary_structure = make_salary_structure("Monthly Salary Structure Test for Salary Slip YTD", "Monthly", employee=applicant, company="_Test Company", currency="INR", payroll_period=payroll_period) @@ -309,15 +315,13 @@ class TestSalarySlip(unittest.TestCase): create_salary_slips_for_payroll_period(applicant, salary_structure.name, payroll_period, deduct_random=False) - salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date'], filters={'employee_name': + salary_slips = frappe.get_all('Salary Slip', fields=['year_to_date', 'net_pay'], filters={'employee_name': 'test_ytd@salary.com'}, order_by = 'posting_date') - net_pay = 70026.00 - month = 1 + year_to_date = 0 for slip in salary_slips: - year_to_date = month * net_pay + year_to_date += slip.net_pay self.assertEqual(slip.year_to_date, year_to_date) - month += 1 def test_tax_for_payroll_period(self): data = {} @@ -439,10 +443,7 @@ def make_employee_salary_slip(user, payroll_frequency, salary_structure=None): salary_structure = payroll_frequency + " Salary Structure Test for Salary Slip" employee = frappe.db.get_value("Employee", {"user_id": user}) - if not frappe.db.exists('Salary Structure', salary_structure): - salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee) - else: - salary_structure_doc = frappe.get_doc('Salary Structure', salary_structure) + salary_structure_doc = make_salary_structure(salary_structure, payroll_frequency, employee=employee) salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": user})}) if not salary_slip_name: @@ -660,7 +661,8 @@ def create_benefit_claim(employee, payroll_period, amount, component): }).submit() return claim_date -def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=None): +def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = False, dont_submit = False, currency=None, + company=None): if not currency: currency = erpnext.get_default_currency() @@ -687,6 +689,10 @@ def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = income_tax_slab = frappe.new_doc("Income Tax Slab") income_tax_slab.name = "Tax Slab: " + payroll_period.name income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2) + + if company: + income_tax_slab.company = company + income_tax_slab.currency = currency if allow_tax_exemption: diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index e1c6a008aa..2b249c7a19 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -154,9 +154,8 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non if not payroll_period: payroll_period = create_payroll_period() - income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) - else: - income_tax_slab = frappe.db.get_value('Income Tax Slab', "Tax Slab: " + payroll_period.name) + + income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") salary_structure_assignment.employee = employee From 97d055dfc34ba987f538a1f794bcc9e6eb97e87e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 30 Dec 2020 14:06:13 +0530 Subject: [PATCH 12/13] fix: Test Case --- erpnext/payroll/doctype/salary_slip/salary_slip.py | 2 +- .../doctype/salary_structure/test_salary_structure.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 9f46d50e58..99d8a8317c 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -1163,7 +1163,7 @@ class SalarySlip(TransactionBase): 'end_date' : ['<', self.start_date] }) - year_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0 + month_to_date = flt(salary_slip_sum[0].sum) if salary_slip_sum else 0.0 month_to_date += self.net_pay self.month_to_date = month_to_date diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index 2b249c7a19..f2fb558a14 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -155,7 +155,10 @@ def create_salary_structure_assignment(employee, salary_structure, from_date=Non if not payroll_period: payroll_period = create_payroll_period() - income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) + income_tax_slab = frappe.db.get_value("Income Tax Slab", {"currency": currency}) + + if not income_tax_slab: + income_tax_slab = create_tax_slab(payroll_period, allow_tax_exemption=True, currency=currency) salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") salary_structure_assignment.employee = employee From 66dcaf3ab2cda4663317827e20ca87dc1fa3181b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 30 Dec 2020 15:47:22 +0530 Subject: [PATCH 13/13] fix: Salary structure assignment in tests --- .../income_tax_slab/income_tax_slab.py | 2 +- .../doctype/salary_slip/test_salary_slip.py | 20 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py index e2b22a6ce9..81e364778c 100644 --- a/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py +++ b/erpnext/payroll/doctype/income_tax_slab/income_tax_slab.py @@ -3,7 +3,7 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe +#import frappe import erpnext from frappe.model.document import Document diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index 9e3e707f39..bb310c4d87 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -9,7 +9,7 @@ import calendar import random from erpnext.accounts.utils import get_fiscal_year from frappe.utils.make_random import get_random -from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day +from frappe.utils import getdate, nowdate, add_days, add_months, flt, get_first_day, get_last_day, cstr from erpnext.payroll.doctype.salary_structure.salary_structure import make_salary_slip from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_month_details from erpnext.hr.doctype.employee.test_employee import make_employee @@ -240,8 +240,7 @@ class TestSalarySlip(unittest.TestCase): interest_income_account='Interest Income Account - _TC', penalty_income_account='Penalty Income Account - _TC') - payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company", - start_date=getdate("2019-04-01"), end_date=getdate("2020-03-31")) + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR', payroll_period=payroll_period) @@ -300,8 +299,7 @@ class TestSalarySlip(unittest.TestCase): applicant = make_employee("test_ytd@salary.com", company="_Test Company") - payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company", - start_date=getdate("2019-04-01"), end_date=getdate("2020-03-31")) + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") create_tax_slab(payroll_period, allow_tax_exemption=True, currency="INR", effective_date=getdate("2019-04-01"), company="_Test Company") @@ -666,6 +664,9 @@ def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = if not currency: currency = erpnext.get_default_currency() + if company: + currency = erpnext.get_company_currency(company) + slabs = [ { "from_amount": 250000, @@ -684,15 +685,12 @@ def create_tax_slab(payroll_period, effective_date = None, allow_tax_exemption = } ] - income_tax_slab_name = frappe.db.get_value("Income Tax Slab", "Tax Slab: " + payroll_period.name) + income_tax_slab_name = frappe.db.get_value("Income Tax Slab", {"currency": currency}) if not income_tax_slab_name: income_tax_slab = frappe.new_doc("Income Tax Slab") - income_tax_slab.name = "Tax Slab: " + payroll_period.name + income_tax_slab.name = "Tax Slab: " + payroll_period.name + " " + cstr(currency) income_tax_slab.effective_from = effective_date or add_days(payroll_period.start_date, -2) - - if company: - income_tax_slab.company = company - + income_tax_slab.company = company or '' income_tax_slab.currency = currency if allow_tax_exemption: