Employee benefit - Late employee benefit application (#14465)

* HR Utils - get salary slip total benefit given for a payroll period

* Late employee benefit application

* Additional Salary - code refactor - get_amount

* new line in salary detail json

* Employee benefit late application - validation refactor

* Codacy fix
This commit is contained in:
Jamsheer 2018-06-12 11:30:59 +05:30 committed by Nabin Hait
parent 2354c1eba3
commit 8d66f1e45d
7 changed files with 95 additions and 33 deletions

View File

@ -25,11 +25,6 @@ class AdditionalSalary(Document):
frappe.throw(_("To date can not greater than employee's relieving date"))
def get_amount(self, sal_start_date, sal_end_date):
# If additional salary dates in between the salary slip dates
# then return complete additional salary amount
if getdate(sal_start_date) <= getdate(self.from_date) <= getdate(sal_end_date)\
and getdate(sal_end_date) >= getdate(self.to_date) >= getdate(sal_start_date):
return self.amount
start_date = getdate(sal_start_date)
end_date = getdate(sal_end_date)
total_days = date_diff(getdate(self.to_date), getdate(self.from_date)) + 1
@ -38,12 +33,9 @@ class AdditionalSalary(Document):
start_date = getdate(self.from_date)
if getdate(sal_end_date) > getdate(self.to_date):
end_date = getdate(self.to_date)
no_of_days = date_diff(getdate(end_date), getdate(start_date))
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):
additional_components = frappe.db.sql("""

View File

@ -11,25 +11,53 @@ frappe.ui.form.on('Employee Benefit Application', {
});
},
employee: function(frm) {
if(frm.doc.employee && frm.doc.date){
frappe.call({
method: "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits",
args:{
employee: frm.doc.employee,
on_date: frm.doc.date
},
callback: function (data) {
if(!data.exc){
if(data.message){
frm.set_value("max_benefits", data.message);
}
}
}
});
var method, args;
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
method = "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
args = {
employee: frm.doc.employee,
on_date: frm.doc.date,
payroll_period: frm.doc.payroll_period
};
get_max_benefits(frm, method, args);
}
else if(frm.doc.employee && frm.doc.date){
method = "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits";
args = {
employee: frm.doc.employee,
on_date: frm.doc.date
};
get_max_benefits(frm, method, args);
}
},
payroll_period: function(frm) {
var method, args;
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
method = "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
args = {
employee: frm.doc.employee,
on_date: frm.doc.date,
payroll_period: frm.doc.payroll_period
};
get_max_benefits(frm, method, args);
}
}
});
var get_max_benefits=function(frm, method, args) {
frappe.call({
method: method,
args: args,
callback: function (data) {
if(!data.exc){
if(data.message){
frm.set_value("max_benefits", data.message);
}
}
}
});
};
frappe.ui.form.on("Employee Benefit Application Detail",{
amount: function(frm) {
calculate_all(frm.doc);

View File

@ -5,10 +5,11 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import date_diff, getdate
from frappe.utils import date_diff, getdate, rounded
from frappe.model.document import Document
from erpnext.hr.doctype.payroll_period.payroll_period import get_payroll_period_days
from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure
from erpnext.hr.utils import get_sal_slip_total_benefit_given
class EmployeeBenefitApplication(Document):
def validate(self):
@ -41,9 +42,10 @@ class EmployeeBenefitApplication(Document):
pro_rata_amount += max_benefit_amount
else:
non_pro_rata_amount += max_benefit_amount
if pro_rata_amount == 0 and non_pro_rata_amount == 0:
frappe.throw(_("Please add the remainig benefits {0} to any of the existing component").format(self.remainig_benefits))
elif non_pro_rata_amount > 0 and non_pro_rata_amount < self.remainig_benefits:
elif non_pro_rata_amount > 0 and non_pro_rata_amount < rounded(self.remainig_benefits):
frappe.throw(_("You can claim only an amount of {0}, the rest amount {1} should be in the application \
as pro-rata component").format(non_pro_rata_amount, self.remainig_benefits - non_pro_rata_amount))
elif non_pro_rata_amount == 0:
@ -65,7 +67,9 @@ class EmployeeBenefitApplication(Document):
for employee_benefit in self.employee_benefits:
if employee_benefit.earning_component == earning_component_name:
benefit_amount += employee_benefit.amount
if benefit_amount > max_benefit_amount:
prev_sal_slip_flexi_amount = get_sal_slip_total_benefit_given(self.employee, frappe.get_doc("Payroll Period", self.payroll_period), earning_component_name)
benefit_amount += prev_sal_slip_flexi_amount
if rounded(benefit_amount, 2) > max_benefit_amount:
frappe.throw(_("Maximum benefit amount of component {0} exceeds {1}").format(earning_component_name, max_benefit_amount))
def validate_duplicate_on_payroll_period(self):
@ -87,10 +91,17 @@ def get_max_benefits(employee, on_date):
max_benefits = frappe.db.get_value("Salary Structure", sal_struct, "max_benefits")
if max_benefits > 0:
return max_benefits
else:
frappe.throw(_("Employee {0} has no max benefits in salary structure {1}").format(employee, sal_struct[0][0]))
else:
frappe.throw(_("Employee {0} has no salary structure assigned").format(employee))
return False
@frappe.whitelist()
def get_max_benefits_remaining(employee, on_date, payroll_period):
max_benefits = get_max_benefits(employee, on_date)
if max_benefits and max_benefits > 0:
payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period)
# Get all salary slip flexi amount in the payroll period
prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given(employee, payroll_period_obj)
return max_benefits - prev_sal_slip_flexi_total
return max_benefits
def get_benefit_component_amount(employee, start_date, end_date, struct_row, sal_struct):
# Considering there is only one application for an year

View File

@ -13,6 +13,8 @@ from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment
class EmployeeBenefitClaim(Document):
def validate(self):
max_benefits = get_max_benefits(self.employee, self.claim_date)
if not max_benefits or max_benefits <= 0:
frappe.throw(_("Employee {0} has no maximum benefit amount").format(self.employee))
payroll_period = get_payroll_period(self.claim_date, self.claim_date, frappe.db.get_value("Employee", self.employee, "company"))
self.validate_max_benefit_for_component(payroll_period)
self.validate_max_benefit_for_sal_struct(max_benefits)

View File

@ -606,4 +606,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
}
}

View File

@ -107,7 +107,8 @@ class SalarySlip(TransactionBase):
'depends_on_lwp' : struct_row.depends_on_lwp,
'salary_component' : struct_row.salary_component,
'abbr' : struct_row.abbr,
'do_not_include_in_total' : struct_row.do_not_include_in_total
'do_not_include_in_total' : struct_row.do_not_include_in_total,
'is_flexible_benefit': struct_row.is_flexible_benefit
})
else:
component_row.amount = amount

View File

@ -350,3 +350,31 @@ def get_annual_component_pay(frequency, amount):
return amount * 12
elif frequency == "Bimonthly":
return amount * 6
def get_sal_slip_total_benefit_given(employee, payroll_period, component=False):
total_given_benefit_amount = 0
query = """
select sum(sd.amount) as 'total_amount'
from `tabSalary Slip` ss, `tabSalary Detail` sd
where ss.employee=%(employee)s
and ss.docstatus = 1 and ss.name = sd.parent
and sd.is_flexible_benefit = 1 and sd.parentfield = "earnings"
and sd.parenttype = "Salary Slip"
and (ss.start_date between %(start_date)s and %(end_date)s
or ss.end_date between %(start_date)s and %(end_date)s
or (ss.start_date < %(start_date)s and ss.end_date > %(end_date)s))
"""
if component:
query += "and sd.salary_component = %(component)s"
sum_of_given_benefit = frappe.db.sql(query, {
'employee': employee,
'start_date': payroll_period.start_date,
'end_date': payroll_period.end_date,
'component': component
}, as_dict=True)
if sum_of_given_benefit and sum_of_given_benefit[0].total_amount > 0:
total_given_benefit_amount = sum_of_given_benefit[0].total_amount
return total_given_benefit_amount