Merge branch 'develop' of https://github.com/frappe/erpnext into loan_fixes_phase_2

This commit is contained in:
Deepesh Garg
2021-04-06 23:53:34 +05:30
259 changed files with 4285 additions and 3026 deletions

View File

@@ -163,7 +163,6 @@
"read_only": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
"fieldname": "currency",
"fieldtype": "Link",
@@ -176,7 +175,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-20 17:51:13.419716",
"modified": "2021-03-31 14:45:48.566756",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Additional Salary",

View File

@@ -9,17 +9,10 @@ from frappe import _, bold
from frappe.utils import getdate, date_diff, comma_and, formatdate
class AdditionalSalary(Document):
def on_submit(self):
if self.ref_doctype == "Employee Advance" and self.ref_docname:
frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount)
def before_insert(self):
if frappe.db.exists("Additional Salary", {"employee": self.employee, "salary_component": self.salary_component,
"amount": self.amount, "payroll_date": self.payroll_date, "company": self.company, "docstatus": 1}):
frappe.throw(_("Additional Salary Component Exists."))
def validate(self):
self.validate_dates()
self.validate_salary_structure()
@@ -89,10 +82,11 @@ class AdditionalSalary(Document):
no_of_days = date_diff(getdate(end_date), getdate(start_date)) + 1
return amount_per_day * no_of_days
@frappe.whitelist()
def get_additional_salary_component(employee, start_date, end_date, component_type):
additional_salaries = frappe.db.sql("""
select name, salary_component, type, amount, overwrite_salary_structure_amount, deduct_full_tax_on_selected_payroll_date
def get_additional_salaries(employee, start_date, end_date, component_type):
additional_salary_list = frappe.db.sql("""
select name, salary_component as component, type, amount,
overwrite_salary_structure_amount as overwrite,
deduct_full_tax_on_selected_payroll_date
from `tabAdditional Salary`
where employee=%(employee)s
and docstatus = 1
@@ -102,7 +96,7 @@ def get_additional_salary_component(employee, start_date, end_date, component_ty
from_date <= %(to_date)s and to_date >= %(to_date)s
)
and type = %(component_type)s
order by salary_component, overwrite_salary_structure_amount DESC
order by salary_component, overwrite ASC
""", {
'employee': employee,
'from_date': start_date,
@@ -110,38 +104,18 @@ def get_additional_salary_component(employee, start_date, end_date, component_ty
'component_type': "Earning" if component_type == "earnings" else "Deduction"
}, as_dict=1)
existing_salary_components= []
salary_components_details = {}
additional_salary_details = []
additional_salaries = []
components_to_overwrite = []
overwrites_components = [ele.salary_component for ele in additional_salaries if ele.overwrite_salary_structure_amount == 1]
for d in additional_salary_list:
if d.overwrite:
if d.component in components_to_overwrite:
frappe.throw(_("Multiple Additional Salaries with overwrite "
"property exist for Salary Component {0} between {1} and {2}.").format(
frappe.bold(d.component), start_date, end_date), title=_("Error"))
component_fields = ["depends_on_payment_days", "salary_component_abbr", "is_tax_applicable", "variable_based_on_taxable_salary", 'type']
for d in additional_salaries:
components_to_overwrite.append(d.component)
if d.salary_component not in existing_salary_components:
component = frappe.get_all("Salary Component", filters={'name': d.salary_component}, fields=component_fields)
struct_row = frappe._dict({'salary_component': d.salary_component})
if component:
struct_row.update(component[0])
additional_salaries.append(d)
struct_row['deduct_full_tax_on_selected_payroll_date'] = d.deduct_full_tax_on_selected_payroll_date
struct_row['is_additional_component'] = 1
salary_components_details[d.salary_component] = struct_row
if overwrites_components.count(d.salary_component) > 1:
frappe.throw(_("Multiple Additional Salaries with overwrite property exist for Salary Component: {0} between {1} and {2}.".format(d.salary_component, start_date, end_date)), title=_("Error"))
else:
additional_salary_details.append({
'name': d.name,
'component': d.salary_component,
'amount': d.amount,
'type': d.type,
'overwrite': d.overwrite_salary_structure_amount,
})
existing_salary_components.append(d.salary_component)
return salary_components_details, additional_salary_details
return additional_salaries

View File

@@ -124,7 +124,6 @@
"read_only": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
"fieldname": "currency",
"fieldtype": "Link",
@@ -148,7 +147,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-12-14 15:52:08.566418",
"modified": "2021-03-31 14:46:22.465521",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Benefit Application",

View File

@@ -21,7 +21,6 @@ frappe.ui.form.on('Employee Benefit Claim', {
callback: function(r) {
if (r.message) {
frm.set_value('currency', r.message);
frm.set_df_property('currency', 'hidden', 0);
}
}
});

View File

@@ -125,10 +125,9 @@
"label": "Attachments"
},
{
"default": "Company:company:default_currency",
"depends_on": "eval: doc.employee",
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 1,
"label": "Currency",
"options": "Currency",
"read_only": 1,
@@ -145,7 +144,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-11-25 11:49:56.097352",
"modified": "2021-03-31 15:51:51.489269",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Benefit Claim",

View File

@@ -75,7 +75,6 @@
"reqd": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
"fieldname": "currency",
"fieldtype": "Link",
@@ -95,7 +94,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-20 17:22:16.468042",
"modified": "2021-03-31 14:48:00.919839",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Incentive",

View File

@@ -47,5 +47,26 @@ frappe.ui.form.on('Employee Tax Exemption Declaration', {
});
}).addClass("btn-primary");
}
},
employee: function(frm) {
if (frm.doc.employee) {
frm.trigger('get_employee_currency');
}
},
get_employee_currency: function(frm) {
frappe.call({
method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
args: {
employee: frm.doc.employee,
},
callback: function(r) {
if (r.message) {
frm.set_value('currency', r.message);
frm.refresh_fields();
}
}
});
}
});

View File

@@ -108,7 +108,7 @@
"read_only": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval: doc.employee",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
@@ -119,7 +119,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-20 16:42:24.493761",
"modified": "2021-03-31 20:41:57.387749",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Declaration",

View File

@@ -58,5 +58,26 @@ frappe.ui.form.on('Employee Tax Exemption Proof Submission', {
currency: function(frm) {
frm.refresh_fields();
}
},
employee: function(frm) {
if (frm.doc.employee) {
frm.trigger('get_employee_currency');
}
},
get_employee_currency: function(frm) {
frappe.call({
method: "erpnext.payroll.doctype.salary_structure_assignment.salary_structure_assignment.get_employee_currency",
args: {
employee: frm.doc.employee,
},
callback: function(r) {
if (r.message) {
frm.set_value('currency', r.message);
frm.refresh_fields();
}
}
});
},
});

View File

@@ -131,7 +131,7 @@
"read_only": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval: doc.employee",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
@@ -142,7 +142,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-20 16:47:03.410020",
"modified": "2021-03-31 20:48:32.639885",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Employee Tax Exemption Proof Submission",

View File

@@ -15,9 +15,12 @@ from frappe.utils import getdate, add_days, get_datetime, flt
test_dependencies = ["Salary Component", "Salary Slip", "Account"]
class TestGratuity(unittest.TestCase):
def setUp(self):
@classmethod
def setUpClass(cls):
make_earning_salary_component(setup=True, test_tax=True, company_list=['_Test Company'])
make_deduction_salary_component(setup=True, test_tax=True, company_list=['_Test Company'])
def setUp(self):
frappe.db.sql("DELETE FROM `tabGratuity`")
frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")

View File

@@ -93,7 +93,7 @@
"options": "Income Tax Slab Other Charges"
},
{
"default": "Company:company:default_currency",
"fetch_from": "company.default_currency",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
@@ -104,7 +104,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-19 13:54:24.728075",
"modified": "2021-03-31 20:53:33.323712",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Income Tax Slab",

View File

@@ -95,6 +95,7 @@ class PayrollEntry(Document):
return emp_list
@frappe.whitelist()
def fill_employee_details(self):
self.set('employees', [])
employees = self.get_emp_list()
@@ -142,6 +143,7 @@ class PayrollEntry(Document):
if not self.get(fieldname):
frappe.throw(_("Please set {0}").format(self.meta.get_label(fieldname)))
@frappe.whitelist()
def create_salary_slips(self):
"""
Creates salary slip for selected employees if already not created
@@ -329,6 +331,7 @@ class PayrollEntry(Document):
amount = flt(amount) * flt(conversion_rate)
return exchange_rate, amount
@frappe.whitelist()
def make_payment_entry(self):
self.check_permission('write')

View File

@@ -12,7 +12,7 @@ from erpnext.hr.doctype.employee.test_employee import make_employee
from erpnext.payroll.doctype.salary_slip.test_salary_slip import get_salary_component_account, \
make_earning_salary_component, make_deduction_salary_component, create_account, make_employee_salary_slip
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure, create_salary_structure_assignment
from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry
from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
class TestPayrollEntry(unittest.TestCase):
@@ -168,15 +168,23 @@ class TestPayrollEntry(unittest.TestCase):
salary_structure = "Test Salary Structure for Loan"
make_salary_structure(salary_structure, "Monthly", employee=employee_doc.name, company="_Test Company", currency=company_doc.default_currency)
if not frappe.db.exists("Loan Type", "Car Loan"):
create_loan_accounts()
create_loan_type("Car Loan", 500000, 8.4,
is_term_loan=1,
mode_of_payment='Cash',
payment_account='Payment Account - _TC',
loan_account='Loan Account - _TC',
interest_income_account='Interest Income Account - _TC',
penalty_income_account='Penalty Income Account - _TC')
loan = create_loan(applicant, "Car Loan", 280000, "Repay Over Number of Periods", 20, posting_date=add_months(nowdate(), -1))
loan.repay_from_salary = 1
loan.submit()
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
dates = get_start_end_dates('Monthly', nowdate())
make_payroll_entry(company="_Test Company", start_date=dates.start_date, payable_account=company_doc.default_payroll_payable_account,
currency=company_doc.default_currency, end_date=dates.end_date, branch=branch, cost_center="Main - _TC", payment_account="Cash - _TC")
@@ -267,4 +275,4 @@ def get_salary_slip(user, period, salary_structure):
salary_slip.calculate_net_pay()
salary_slip.db_update()
return salary_slip
return salary_slip

View File

@@ -93,7 +93,6 @@
"reqd": 1
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.employee)",
"fieldname": "currency",
"fieldtype": "Link",
@@ -106,7 +105,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-10-20 17:27:47.003134",
"modified": "2021-03-31 14:50:29.401020",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Retention Bonus",

View File

@@ -74,43 +74,46 @@ frappe.ui.form.on("Salary Slip", {
if (!frm.doc.letter_head && company.default_letter_head) {
frm.set_value('letter_head', company.default_letter_head);
}
},
currency: function(frm) {
frm.trigger("set_dynamic_labels");
},
set_dynamic_labels: function(frm) {
var company_currency = frm.doc.company? erpnext.get_currency(frm.doc.company): frappe.defaults.get_default("currency");
frappe.run_serially([
() => frm.events.set_exchange_rate(frm, company_currency),
() => frm.events.change_form_labels(frm, company_currency),
() => frm.events.change_grid_labels(frm),
() => frm.refresh_fields()
]);
if (frm.doc.employee && frm.doc.currency) {
frappe.run_serially([
() => frm.events.set_exchange_rate(frm, company_currency),
() => frm.events.change_form_labels(frm, company_currency),
() => frm.events.change_grid_labels(frm),
() => frm.refresh_fields()
]);
}
},
set_exchange_rate: function(frm, company_currency) {
if (frm.doc.docstatus === 0) {
if (frm.doc.currency) {
var from_currency = frm.doc.currency;
if (from_currency != company_currency) {
frm.events.hide_loan_section(frm);
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
from_currency: from_currency,
to_currency: company_currency,
},
callback: function(r) {
frm.set_value("exchange_rate", flt(r.message));
frm.set_df_property('exchange_rate', 'hidden', 0);
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
+ " = [?] " + company_currency);
}
});
} else {
frm.set_value("exchange_rate", 1.0);
frm.set_df_property('exchange_rate', 'hidden', 1);
frm.set_df_property("exchange_rate", "description", "" );
}
if (frm.doc.currency) {
var from_currency = frm.doc.currency;
if (from_currency != company_currency) {
frm.events.hide_loan_section(frm);
frappe.call({
method: "erpnext.setup.utils.get_exchange_rate",
args: {
from_currency: from_currency,
to_currency: company_currency,
},
callback: function(r) {
frm.set_value("exchange_rate", flt(r.message));
frm.set_df_property("exchange_rate", "hidden", 0);
frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
+ " = [?] " + company_currency);
}
});
} else {
frm.set_value("exchange_rate", 1.0);
frm.set_df_property("exchange_rate", "hidden", 1);
frm.set_df_property("exchange_rate", "description", "");
}
}
},
@@ -213,7 +216,7 @@ frappe.ui.form.on('Salary Slip Timesheet', {
});
var set_totals = function(frm) {
if (frm.doc.docstatus === 0) {
if (frm.doc.docstatus === 0 && frm.doc.doctype === "Salary Slip") {
if (frm.doc.earnings || frm.doc.deductions) {
frappe.call({
method: "set_totals",

View File

@@ -500,7 +500,6 @@
"fieldtype": "Column Break"
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
"fetch_from": "salary_structure.currency",
"fieldname": "currency",
@@ -632,7 +631,7 @@
"idx": 9,
"is_submittable": 1,
"links": [],
"modified": "2021-02-19 11:48:05.383945",
"modified": "2021-03-31 15:39:28.817166",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Slip",

View File

@@ -13,7 +13,7 @@ from erpnext.payroll.doctype.payroll_entry.payroll_entry import get_start_end_da
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.payroll.doctype.additional_salary.additional_salary import get_additional_salary_component
from erpnext.payroll.doctype.additional_salary.additional_salary import get_additional_salaries
from erpnext.payroll.doctype.payroll_period.payroll_period import get_period_factor, get_payroll_period
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
@@ -142,6 +142,7 @@ class SalarySlip(TransactionBase):
self.start_date = date_details.start_date
self.end_date = date_details.end_date
@frappe.whitelist()
def get_emp_and_working_day_details(self):
'''First time, load all the components from salary structure'''
if self.employee:
@@ -524,7 +525,7 @@ class SalarySlip(TransactionBase):
except NameError as err:
frappe.throw(_("{0} <br> This error can be due to missing or deleted field.").format(err),
title=_("Name error"))
title=_("Name error"))
except SyntaxError as err:
frappe.throw(_("Syntax error in formula or condition: {0}").format(err))
except Exception as e:
@@ -558,15 +559,16 @@ class SalarySlip(TransactionBase):
self.update_component_row(frappe._dict(last_benefit.struct_row), amount, "earnings")
def add_additional_salary_components(self, component_type):
salary_components_details, additional_salary_details = get_additional_salary_component(self.employee,
additional_salaries = get_additional_salaries(self.employee,
self.start_date, self.end_date, component_type)
if salary_components_details and additional_salary_details:
for additional_salary in additional_salary_details:
additional_salary =frappe._dict(additional_salary)
amount = additional_salary.amount
overwrite = additional_salary.overwrite
self.update_component_row(frappe._dict(salary_components_details[additional_salary.component]), amount,
component_type, overwrite=overwrite, additional_salary=additional_salary.name)
for additional_salary in additional_salaries:
self.update_component_row(
get_salary_component_data(additional_salary.component),
additional_salary.amount,
component_type,
additional_salary
)
def add_tax_components(self, payroll_period):
# Calculate variable_based_on_taxable_salary after all components updated in salary slip
@@ -583,47 +585,62 @@ class SalarySlip(TransactionBase):
for d in tax_components:
tax_amount = self.calculate_variable_based_on_taxable_salary(d, payroll_period)
tax_row = self.get_salary_slip_row(d)
tax_row = get_salary_component_data(d)
self.update_component_row(tax_row, tax_amount, "deductions")
def update_component_row(self, struct_row, amount, key, overwrite=1, additional_salary = ''):
def update_component_row(self, component_data, amount, component_type, additional_salary=None):
component_row = None
for d in self.get(key):
if d.salary_component == struct_row.salary_component:
for d in self.get(component_type):
if d.salary_component != component_data.salary_component:
continue
if (
not d.additional_salary
and (not additional_salary or additional_salary.overwrite)
or additional_salary
and additional_salary.name == d.additional_salary
):
component_row = d
break
if not component_row or (struct_row.get("is_additional_component") and not overwrite):
if amount:
self.append(key, {
'amount': amount,
'default_amount': amount if not struct_row.get("is_additional_component") else 0,
'depends_on_payment_days' : struct_row.depends_on_payment_days,
'salary_component' : struct_row.salary_component,
'abbr' : struct_row.abbr or struct_row.get("salary_component_abbr"),
'additional_salary': additional_salary,
'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,
'deduct_full_tax_on_selected_payroll_date': struct_row.deduct_full_tax_on_selected_payroll_date,
'additional_amount': amount if struct_row.get("is_additional_component") else 0,
'exempted_from_income_tax': struct_row.exempted_from_income_tax
})
if additional_salary and additional_salary.overwrite:
# Additional Salary with overwrite checked, remove default rows of same component
self.set(component_type, [
d for d in self.get(component_type)
if d.salary_component != component_data.salary_component
or d.additional_salary and additional_salary.name != d.additional_salary
or d == component_row
])
if not component_row:
if not amount:
return
component_row = self.append(component_type)
for attr in (
'depends_on_payment_days', 'salary_component',
'do_not_include_in_total', 'is_tax_applicable',
'is_flexible_benefit', 'variable_based_on_taxable_salary',
'exempted_from_income_tax'
):
component_row.set(attr, component_data.get(attr))
abbr = component_data.get('abbr') or component_data.get('salary_component_abbr')
component_row.set('abbr', abbr)
if additional_salary:
component_row.default_amount = 0
component_row.additional_amount = amount
component_row.additional_salary = additional_salary.name
component_row.deduct_full_tax_on_selected_payroll_date = \
additional_salary.deduct_full_tax_on_selected_payroll_date
else:
if struct_row.get("is_additional_component"):
if overwrite:
component_row.additional_amount = amount - component_row.get("default_amount", 0)
component_row.additional_salary = additional_salary
else:
component_row.additional_amount = amount
component_row.default_amount = amount
component_row.additional_amount = 0
component_row.deduct_full_tax_on_selected_payroll_date = \
component_data.deduct_full_tax_on_selected_payroll_date
if not overwrite and component_row.default_amount:
amount += component_row.default_amount
else:
component_row.default_amount = amount
component_row.amount = amount
component_row.deduct_full_tax_on_selected_payroll_date = struct_row.deduct_full_tax_on_selected_payroll_date
component_row.amount = amount
def calculate_variable_based_on_taxable_salary(self, tax_component, payroll_period):
if not payroll_period:
@@ -950,26 +967,13 @@ class SalarySlip(TransactionBase):
return frappe.safe_eval(condition, self.whitelisted_globals, data)
except NameError as err:
frappe.throw(_("{0} <br> This error can be due to missing or deleted field.").format(err),
title=_("Name error"))
title=_("Name error"))
except SyntaxError as err:
frappe.throw(_("Syntax error in condition: {0}").format(err))
except Exception as e:
frappe.throw(_("Error in formula or condition: {0}").format(e))
raise
def get_salary_slip_row(self, salary_component):
component = frappe.get_doc("Salary Component", salary_component)
# Data for update_component_row
struct_row = frappe._dict()
struct_row['depends_on_payment_days'] = component.depends_on_payment_days
struct_row['salary_component'] = component.name
struct_row['abbr'] = component.salary_component_abbr
struct_row['do_not_include_in_total'] = component.do_not_include_in_total
struct_row['is_tax_applicable'] = component.is_tax_applicable
struct_row['is_flexible_benefit'] = component.is_flexible_benefit
struct_row['variable_based_on_taxable_salary'] = component.variable_based_on_taxable_salary
return struct_row
def get_component_totals(self, component_type, depends_on_payment_days=0):
joining_date, relieving_date = frappe.get_cached_value("Employee", self.employee,
["date_of_joining", "relieving_date"])
@@ -1032,7 +1036,6 @@ class SalarySlip(TransactionBase):
self.total_loan_repayment += payment.total_payment
def get_loan_details(self):
return frappe.get_all("Loan",
fields=["name", "interest_income_account", "loan_account", "loan_type"],
filters = {
@@ -1115,10 +1118,12 @@ class SalarySlip(TransactionBase):
self.bank_name = emp.bank_name
self.bank_account_no = emp.bank_ac_no
@frappe.whitelist()
def process_salary_based_on_working_days(self):
self.get_working_days_details(lwp=self.leave_without_pay)
self.calculate_net_pay()
@frappe.whitelist()
def set_totals(self):
self.gross_pay = 0.0
if self.salary_slip_based_on_timesheet == 1:
@@ -1263,3 +1268,19 @@ 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())
def get_salary_component_data(component):
return frappe.get_value(
"Salary Component",
component,
[
"name as salary_component",
"depends_on_payment_days",
"salary_component_abbr as abbr",
"do_not_include_in_total",
"is_tax_applicable",
"is_flexible_benefit",
"variable_based_on_taxable_salary",
],
as_dict=1,
)

View File

@@ -246,7 +246,7 @@ class TestSalarySlip(unittest.TestCase):
make_salary_structure("Test Loan Repayment Salary Structure", "Monthly", employee=applicant, currency='INR',
payroll_period=payroll_period)
frappe.db.sql("""delete from `tabLoan""")
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
loan.submit()
@@ -361,7 +361,6 @@ class TestSalarySlip(unittest.TestCase):
# as per assigned salary structure 40500 in monthly salary so 236000*5/100/12
frappe.db.sql("""delete from `tabPayroll Period`""")
frappe.db.sql("""delete from `tabSalary Component`""")
frappe.db.sql("""delete from `tabAdditional Salary`""")
payroll_period = create_payroll_period()

View File

@@ -232,7 +232,7 @@
"idx": 1,
"is_submittable": 1,
"links": [],
"modified": "2020-09-30 11:30:32.190798",
"modified": "2021-03-31 15:41:12.342380",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Structure",

View File

@@ -100,7 +100,7 @@ class SalaryStructure(Document):
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
assign_salary_structure_for_employees(employees, self,
payroll_payable_account=payroll_payable_account,
payroll_payable_account=payroll_payable_account,
from_date=from_date, base=base, variable=variable, income_tax_slab=income_tax_slab)
else:
frappe.msgprint(_("No Employee Found"))

View File

@@ -125,7 +125,6 @@
"options": "Income Tax Slab"
},
{
"default": "Company:company:default_currency",
"depends_on": "eval:(doc.docstatus==1 || doc.salary_structure)",
"fetch_from": "salary_structure.currency",
"fieldname": "currency",
@@ -146,7 +145,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2020-11-30 18:07:48.251311",
"modified": "2021-03-31 15:49:36.361253",
"modified_by": "Administrator",
"module": "Payroll",
"name": "Salary Structure Assignment",