Space to Tabs on salary_slip.py
This commit is contained in:
parent
64f29f819a
commit
a236f4e586
@ -415,7 +415,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2017-04-12 22:47:33.980646",
|
"modified": "2017-04-13 00:47:33.980646",
|
||||||
"modified_by": "chude.osiegbu@manqala.com",
|
"modified_by": "chude.osiegbu@manqala.com",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Salary Detail",
|
"name": "Salary Detail",
|
||||||
|
@ -13,409 +13,409 @@ from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
|||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
|
|
||||||
class SalarySlip(TransactionBase):
|
class SalarySlip(TransactionBase):
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
|
self.name = make_autoname('Sal Slip/' +self.employee + '/.#####')
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.status = self.get_status()
|
self.status = self.get_status()
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
self.check_existing()
|
self.check_existing()
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
self.get_date_details()
|
self.get_date_details()
|
||||||
|
|
||||||
if not (len(self.get("earnings")) or len(self.get("deductions"))):
|
if not (len(self.get("earnings")) or len(self.get("deductions"))):
|
||||||
# get details from salary structure
|
# get details from salary structure
|
||||||
self.get_emp_and_leave_details()
|
self.get_emp_and_leave_details()
|
||||||
else:
|
else:
|
||||||
self.get_leave_details(lwp = self.leave_without_pay)
|
self.get_leave_details(lwp = self.leave_without_pay)
|
||||||
|
|
||||||
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
# if self.salary_slip_based_on_timesheet or not self.net_pay:
|
||||||
self.calculate_net_pay()
|
self.calculate_net_pay()
|
||||||
|
|
||||||
company_currency = erpnext.get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
self.total_in_words = money_in_words(self.rounded_total, company_currency)
|
||||||
|
|
||||||
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
if frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet"):
|
||||||
max_working_hours = frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet")
|
max_working_hours = frappe.db.get_single_value("HR Settings", "max_working_hours_against_timesheet")
|
||||||
if self.salary_slip_based_on_timesheet and (self.total_working_hours > int(max_working_hours)):
|
if self.salary_slip_based_on_timesheet and (self.total_working_hours > int(max_working_hours)):
|
||||||
frappe.msgprint(_("Total working hours should not be greater than max working hours {0}").
|
frappe.msgprint(_("Total working hours should not be greater than max working hours {0}").
|
||||||
format(max_working_hours), alert=True)
|
format(max_working_hours), alert=True)
|
||||||
|
|
||||||
def validate_dates(self):
|
def validate_dates(self):
|
||||||
if date_diff(self.end_date, self.start_date) < 0:
|
if date_diff(self.end_date, self.start_date) < 0:
|
||||||
frappe.throw(_("To date cannot be before From date"))
|
frappe.throw(_("To date cannot be before From date"))
|
||||||
|
|
||||||
def calculate_component_amounts(self):
|
def calculate_component_amounts(self):
|
||||||
if not getattr(self, '_salary_structure_doc', None):
|
if not getattr(self, '_salary_structure_doc', None):
|
||||||
self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)
|
self._salary_structure_doc = frappe.get_doc('Salary Structure', self.salary_structure)
|
||||||
|
|
||||||
data = self.get_data_for_eval()
|
data = self.get_data_for_eval()
|
||||||
|
|
||||||
for key in ('earnings', 'deductions'):
|
for key in ('earnings', 'deductions'):
|
||||||
for struct_row in self._salary_structure_doc.get(key):
|
for struct_row in self._salary_structure_doc.get(key):
|
||||||
amount = self.eval_condition_and_formula(struct_row, data)
|
amount = self.eval_condition_and_formula(struct_row, data)
|
||||||
if amount and struct_row.statistical_component == 0:
|
if amount and struct_row.statistical_component == 0:
|
||||||
self.update_component_row(struct_row, amount, key)
|
self.update_component_row(struct_row, amount, key)
|
||||||
|
|
||||||
def update_component_row(self, struct_row, amount, key):
|
def update_component_row(self, struct_row, amount, key):
|
||||||
component_row = None
|
component_row = None
|
||||||
for d in self.get(key):
|
for d in self.get(key):
|
||||||
if d.salary_component == struct_row.salary_component:
|
if d.salary_component == struct_row.salary_component:
|
||||||
component_row = d
|
component_row = d
|
||||||
|
|
||||||
if not component_row:
|
if not component_row:
|
||||||
self.append(key, {
|
self.append(key, {
|
||||||
'amount': amount,
|
'amount': amount,
|
||||||
'default_amount': amount,
|
'default_amount': amount,
|
||||||
'depends_on_lwp' : struct_row.depends_on_lwp,
|
'depends_on_lwp' : struct_row.depends_on_lwp,
|
||||||
'salary_component' : struct_row.salary_component
|
'salary_component' : struct_row.salary_component
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
component_row.amount = amount
|
component_row.amount = amount
|
||||||
|
|
||||||
def eval_condition_and_formula(self, d, data):
|
def eval_condition_and_formula(self, d, data):
|
||||||
try:
|
try:
|
||||||
if d.condition:
|
if d.condition:
|
||||||
if not frappe.safe_eval(d.condition, None, data):
|
if not frappe.safe_eval(d.condition, None, data):
|
||||||
return None
|
return None
|
||||||
amount = d.amount
|
amount = d.amount
|
||||||
if d.amount_based_on_formula:
|
if d.amount_based_on_formula:
|
||||||
if d.formula:
|
if d.formula:
|
||||||
amount = frappe.safe_eval(d.formula, None, data)
|
amount = frappe.safe_eval(d.formula, None, data)
|
||||||
if amount:
|
if amount:
|
||||||
data[d.abbr] = amount
|
data[d.abbr] = amount
|
||||||
|
|
||||||
return amount
|
return amount
|
||||||
|
|
||||||
except NameError as err:
|
except NameError as err:
|
||||||
frappe.throw(_("Name error: {0}".format(err)))
|
frappe.throw(_("Name error: {0}".format(err)))
|
||||||
except SyntaxError as err:
|
except SyntaxError as err:
|
||||||
frappe.throw(_("Syntax error in formula or condition: {0}".format(err)))
|
frappe.throw(_("Syntax error in formula or condition: {0}".format(err)))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
frappe.throw(_("Error in formula or condition: {0}".format(e)))
|
frappe.throw(_("Error in formula or condition: {0}".format(e)))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_data_for_eval(self):
|
def get_data_for_eval(self):
|
||||||
'''Returns data for evaluating formula'''
|
'''Returns data for evaluating formula'''
|
||||||
data = frappe._dict()
|
data = frappe._dict()
|
||||||
|
|
||||||
data.update(frappe.get_doc("Salary Structure Employee", {"employee": self.employee}).as_dict())
|
data.update(frappe.get_doc("Salary Structure Employee", {"employee": self.employee}).as_dict())
|
||||||
|
|
||||||
data.update(frappe.get_doc("Employee", self.employee).as_dict())
|
data.update(frappe.get_doc("Employee", self.employee).as_dict())
|
||||||
data.update(self.as_dict())
|
data.update(self.as_dict())
|
||||||
|
|
||||||
# set values for components
|
# set values for components
|
||||||
salary_components = frappe.get_all("Salary Component", fields=["salary_component_abbr"])
|
salary_components = frappe.get_all("Salary Component", fields=["salary_component_abbr"])
|
||||||
for sc in salary_components:
|
for sc in salary_components:
|
||||||
data.setdefault(sc.salary_component_abbr, 0)
|
data.setdefault(sc.salary_component_abbr, 0)
|
||||||
|
|
||||||
for key in ('earnings', 'deductions'):
|
for key in ('earnings', 'deductions'):
|
||||||
for d in self.get(key):
|
for d in self.get(key):
|
||||||
data[d.abbr] = d.amount
|
data[d.abbr] = d.amount
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_emp_and_leave_details(self):
|
def get_emp_and_leave_details(self):
|
||||||
'''First time, load all the components from salary structure'''
|
'''First time, load all the components from salary structure'''
|
||||||
if self.employee:
|
if self.employee:
|
||||||
self.set("earnings", [])
|
self.set("earnings", [])
|
||||||
self.set("deductions", [])
|
self.set("deductions", [])
|
||||||
|
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
self.get_date_details()
|
self.get_date_details()
|
||||||
self.validate_dates()
|
self.validate_dates()
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
self.get_leave_details(joining_date, relieving_date)
|
self.get_leave_details(joining_date, relieving_date)
|
||||||
struct = self.check_sal_struct(joining_date, relieving_date)
|
struct = self.check_sal_struct(joining_date, relieving_date)
|
||||||
|
|
||||||
if struct:
|
if struct:
|
||||||
self._salary_structure_doc = frappe.get_doc('Salary Structure', struct)
|
self._salary_structure_doc = frappe.get_doc('Salary Structure', struct)
|
||||||
self.salary_slip_based_on_timesheet = self._salary_structure_doc.salary_slip_based_on_timesheet or 0
|
self.salary_slip_based_on_timesheet = self._salary_structure_doc.salary_slip_based_on_timesheet or 0
|
||||||
self.set_time_sheet()
|
self.set_time_sheet()
|
||||||
self.pull_sal_struct()
|
self.pull_sal_struct()
|
||||||
|
|
||||||
def set_time_sheet(self):
|
def set_time_sheet(self):
|
||||||
if self.salary_slip_based_on_timesheet:
|
if self.salary_slip_based_on_timesheet:
|
||||||
self.set("timesheets", [])
|
self.set("timesheets", [])
|
||||||
timesheets = frappe.db.sql(""" select * from `tabTimesheet` where employee = %(employee)s and start_date BETWEEN %(start_date)s AND %(end_date)s and (status = 'Submitted' or
|
timesheets = frappe.db.sql(""" select * from `tabTimesheet` where employee = %(employee)s and start_date BETWEEN %(start_date)s AND %(end_date)s and (status = 'Submitted' or
|
||||||
status = 'Billed')""", {'employee': self.employee, 'start_date': self.start_date, 'end_date': self.end_date}, as_dict=1)
|
status = 'Billed')""", {'employee': self.employee, 'start_date': self.start_date, 'end_date': self.end_date}, as_dict=1)
|
||||||
|
|
||||||
for data in timesheets:
|
for data in timesheets:
|
||||||
self.append('timesheets', {
|
self.append('timesheets', {
|
||||||
'time_sheet': data.name,
|
'time_sheet': data.name,
|
||||||
'working_hours': data.total_hours
|
'working_hours': data.total_hours
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_date_details(self):
|
def get_date_details(self):
|
||||||
date_details = get_start_end_dates(self.payroll_frequency, self.start_date or self.posting_date)
|
date_details = get_start_end_dates(self.payroll_frequency, self.start_date or self.posting_date)
|
||||||
self.start_date = date_details.start_date
|
self.start_date = date_details.start_date
|
||||||
self.end_date = date_details.end_date
|
self.end_date = date_details.end_date
|
||||||
|
|
||||||
def check_sal_struct(self, joining_date, relieving_date):
|
def check_sal_struct(self, joining_date, relieving_date):
|
||||||
cond = ''
|
cond = ''
|
||||||
if self.payroll_frequency:
|
if self.payroll_frequency:
|
||||||
cond = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency}
|
cond = """and payroll_frequency = '%(payroll_frequency)s'""" % {"payroll_frequency": self.payroll_frequency}
|
||||||
|
|
||||||
st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee`
|
st_name = frappe.db.sql("""select parent from `tabSalary Structure Employee`
|
||||||
where employee=%s and (from_date <= %s or from_date <= %s)
|
where employee=%s and (from_date <= %s or from_date <= %s)
|
||||||
and (to_date is null or to_date >= %s or to_date >= %s)
|
and (to_date is null or to_date >= %s or to_date >= %s)
|
||||||
and parent in (select name from `tabSalary Structure`
|
and parent in (select name from `tabSalary Structure`
|
||||||
where is_active = 'Yes'%s)
|
where is_active = 'Yes'%s)
|
||||||
"""% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date))
|
"""% ('%s', '%s', '%s','%s','%s', cond),(self.employee, self.start_date, joining_date, self.end_date, relieving_date))
|
||||||
|
|
||||||
if st_name:
|
if st_name:
|
||||||
if len(st_name) > 1:
|
if len(st_name) > 1:
|
||||||
frappe.msgprint(_("Multiple active Salary Structures found for employee {0} for the given dates")
|
frappe.msgprint(_("Multiple active Salary Structures found for employee {0} for the given dates")
|
||||||
.format(self.employee), title=_('Warning'))
|
.format(self.employee), title=_('Warning'))
|
||||||
return st_name and st_name[0][0] or ''
|
return st_name and st_name[0][0] or ''
|
||||||
else:
|
else:
|
||||||
self.salary_structure = None
|
self.salary_structure = None
|
||||||
frappe.msgprint(_("No active or default Salary Structure found for employee {0} for the given dates")
|
frappe.msgprint(_("No active or default Salary Structure found for employee {0} for the given dates")
|
||||||
.format(self.employee), title=_('Salary Structure Missing'))
|
.format(self.employee), title=_('Salary Structure Missing'))
|
||||||
|
|
||||||
def pull_sal_struct(self):
|
def pull_sal_struct(self):
|
||||||
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
|
from erpnext.hr.doctype.salary_structure.salary_structure import make_salary_slip
|
||||||
|
|
||||||
if self.salary_slip_based_on_timesheet:
|
if self.salary_slip_based_on_timesheet:
|
||||||
self.salary_structure = self._salary_structure_doc.name
|
self.salary_structure = self._salary_structure_doc.name
|
||||||
self.hour_rate = self._salary_structure_doc.hour_rate
|
self.hour_rate = self._salary_structure_doc.hour_rate
|
||||||
self.total_working_hours = sum([d.working_hours or 0.0 for d in self.timesheets]) or 0.0
|
self.total_working_hours = sum([d.working_hours or 0.0 for d in self.timesheets]) or 0.0
|
||||||
wages_amount = self.hour_rate * self.total_working_hours
|
wages_amount = self.hour_rate * self.total_working_hours
|
||||||
|
|
||||||
self.add_earning_for_hourly_wages(self, self._salary_structure_doc.salary_component, wages_amount)
|
self.add_earning_for_hourly_wages(self, self._salary_structure_doc.salary_component, wages_amount)
|
||||||
|
|
||||||
make_salary_slip(self._salary_structure_doc.name, self)
|
make_salary_slip(self._salary_structure_doc.name, self)
|
||||||
|
|
||||||
def process_salary_structure(self):
|
def process_salary_structure(self):
|
||||||
'''Calculate salary after salary structure details have been updated'''
|
'''Calculate salary after salary structure details have been updated'''
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
self.get_date_details()
|
self.get_date_details()
|
||||||
self.pull_emp_details()
|
self.pull_emp_details()
|
||||||
self.get_leave_details()
|
self.get_leave_details()
|
||||||
self.calculate_net_pay()
|
self.calculate_net_pay()
|
||||||
|
|
||||||
def add_earning_for_hourly_wages(self, doc, salary_component, amount):
|
def add_earning_for_hourly_wages(self, doc, salary_component, amount):
|
||||||
row_exists = False
|
row_exists = False
|
||||||
for row in doc.earnings:
|
for row in doc.earnings:
|
||||||
if row.salary_component == salary_component:
|
if row.salary_component == salary_component:
|
||||||
row.amount = amount
|
row.amount = amount
|
||||||
row_exists = True
|
row_exists = True
|
||||||
break
|
break
|
||||||
|
|
||||||
if not row_exists:
|
if not row_exists:
|
||||||
wages_row = {
|
wages_row = {
|
||||||
"salary_component": salary_component,
|
"salary_component": salary_component,
|
||||||
"abbr": frappe.db.get_value("Salary Component", salary_component, "salary_component_abbr"),
|
"abbr": frappe.db.get_value("Salary Component", salary_component, "salary_component_abbr"),
|
||||||
"amount": self.hour_rate * self.total_working_hours
|
"amount": self.hour_rate * self.total_working_hours
|
||||||
}
|
}
|
||||||
doc.append('earnings', wages_row)
|
doc.append('earnings', wages_row)
|
||||||
|
|
||||||
def pull_emp_details(self):
|
def pull_emp_details(self):
|
||||||
emp = frappe.db.get_value("Employee", self.employee, ["bank_name", "bank_ac_no"], as_dict=1)
|
emp = frappe.db.get_value("Employee", self.employee, ["bank_name", "bank_ac_no"], as_dict=1)
|
||||||
if emp:
|
if emp:
|
||||||
self.bank_name = emp.bank_name
|
self.bank_name = emp.bank_name
|
||||||
self.bank_account_no = emp.bank_ac_no
|
self.bank_account_no = emp.bank_ac_no
|
||||||
|
|
||||||
|
|
||||||
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None):
|
def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None):
|
||||||
if not joining_date:
|
if not joining_date:
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
|
|
||||||
holidays = self.get_holidays_for_employee(self.start_date, self.end_date)
|
holidays = self.get_holidays_for_employee(self.start_date, self.end_date)
|
||||||
working_days = date_diff(self.end_date, self.start_date) + 1
|
working_days = date_diff(self.end_date, self.start_date) + 1
|
||||||
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
||||||
working_days -= len(holidays)
|
working_days -= len(holidays)
|
||||||
if working_days < 0:
|
if working_days < 0:
|
||||||
frappe.throw(_("There are more holidays than working days this month."))
|
frappe.throw(_("There are more holidays than working days this month."))
|
||||||
|
|
||||||
actual_lwp = self.calculate_lwp(holidays, working_days)
|
actual_lwp = self.calculate_lwp(holidays, working_days)
|
||||||
if not lwp:
|
if not lwp:
|
||||||
lwp = actual_lwp
|
lwp = actual_lwp
|
||||||
elif lwp != actual_lwp:
|
elif lwp != actual_lwp:
|
||||||
frappe.msgprint(_("Leave Without Pay does not match with approved Leave Application records"))
|
frappe.msgprint(_("Leave Without Pay does not match with approved Leave Application records"))
|
||||||
|
|
||||||
self.total_working_days = working_days
|
self.total_working_days = working_days
|
||||||
self.leave_without_pay = lwp
|
self.leave_without_pay = lwp
|
||||||
|
|
||||||
payment_days = flt(self.get_payment_days(joining_date, relieving_date)) - flt(lwp)
|
payment_days = flt(self.get_payment_days(joining_date, relieving_date)) - flt(lwp)
|
||||||
self.payment_days = payment_days > 0 and payment_days or 0
|
self.payment_days = payment_days > 0 and payment_days or 0
|
||||||
|
|
||||||
def get_payment_days(self, joining_date, relieving_date):
|
def get_payment_days(self, joining_date, relieving_date):
|
||||||
start_date = getdate(self.start_date)
|
start_date = getdate(self.start_date)
|
||||||
if joining_date:
|
if joining_date:
|
||||||
if getdate(self.start_date) <= joining_date <= getdate(self.end_date):
|
if getdate(self.start_date) <= joining_date <= getdate(self.end_date):
|
||||||
start_date = joining_date
|
start_date = joining_date
|
||||||
elif joining_date > getdate(self.end_date):
|
elif joining_date > getdate(self.end_date):
|
||||||
return
|
return
|
||||||
|
|
||||||
end_date = getdate(self.end_date)
|
end_date = getdate(self.end_date)
|
||||||
if relieving_date:
|
if relieving_date:
|
||||||
if getdate(self.start_date) <= relieving_date <= getdate(self.end_date):
|
if getdate(self.start_date) <= relieving_date <= getdate(self.end_date):
|
||||||
end_date = relieving_date
|
end_date = relieving_date
|
||||||
elif relieving_date < getdate(self.start_date):
|
elif relieving_date < getdate(self.start_date):
|
||||||
frappe.throw(_("Employee relieved on {0} must be set as 'Left'")
|
frappe.throw(_("Employee relieved on {0} must be set as 'Left'")
|
||||||
.format(relieving_date))
|
.format(relieving_date))
|
||||||
|
|
||||||
payment_days = date_diff(end_date, start_date) + 1
|
payment_days = date_diff(end_date, start_date) + 1
|
||||||
|
|
||||||
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")):
|
||||||
holidays = self.get_holidays_for_employee(start_date, end_date)
|
holidays = self.get_holidays_for_employee(start_date, end_date)
|
||||||
payment_days -= len(holidays)
|
payment_days -= len(holidays)
|
||||||
return payment_days
|
return payment_days
|
||||||
|
|
||||||
def get_holidays_for_employee(self, start_date, end_date):
|
def get_holidays_for_employee(self, start_date, end_date):
|
||||||
holiday_list = get_holiday_list_for_employee(self.employee)
|
holiday_list = get_holiday_list_for_employee(self.employee)
|
||||||
holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday`
|
holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday`
|
||||||
where
|
where
|
||||||
parent=%(holiday_list)s
|
parent=%(holiday_list)s
|
||||||
and holiday_date >= %(start_date)s
|
and holiday_date >= %(start_date)s
|
||||||
and holiday_date <= %(end_date)s''', {
|
and holiday_date <= %(end_date)s''', {
|
||||||
"holiday_list": holiday_list,
|
"holiday_list": holiday_list,
|
||||||
"start_date": start_date,
|
"start_date": start_date,
|
||||||
"end_date": end_date
|
"end_date": end_date
|
||||||
})
|
})
|
||||||
|
|
||||||
holidays = [cstr(i) for i in holidays]
|
holidays = [cstr(i) for i in holidays]
|
||||||
|
|
||||||
return holidays
|
return holidays
|
||||||
|
|
||||||
def calculate_lwp(self, holidays, working_days):
|
def calculate_lwp(self, holidays, working_days):
|
||||||
lwp = 0
|
lwp = 0
|
||||||
holidays = "','".join(holidays)
|
holidays = "','".join(holidays)
|
||||||
for d in range(working_days):
|
for d in range(working_days):
|
||||||
dt = add_days(cstr(getdate(self.start_date)), d)
|
dt = add_days(cstr(getdate(self.start_date)), d)
|
||||||
leave = frappe.db.sql("""
|
leave = frappe.db.sql("""
|
||||||
select t1.name, t1.half_day
|
select t1.name, t1.half_day
|
||||||
from `tabLeave Application` t1, `tabLeave Type` t2
|
from `tabLeave Application` t1, `tabLeave Type` t2
|
||||||
where t2.name = t1.leave_type
|
where t2.name = t1.leave_type
|
||||||
and t2.is_lwp = 1
|
and t2.is_lwp = 1
|
||||||
and t1.docstatus = 1
|
and t1.docstatus = 1
|
||||||
and t1.status = 'Approved'
|
and t1.status = 'Approved'
|
||||||
and t1.employee = %(employee)s
|
and t1.employee = %(employee)s
|
||||||
and CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date
|
and CASE WHEN t2.include_holiday != 1 THEN %(dt)s not in ('{0}') and %(dt)s between from_date and to_date
|
||||||
WHEN t2.include_holiday THEN %(dt)s between from_date and to_date
|
WHEN t2.include_holiday THEN %(dt)s between from_date and to_date
|
||||||
END
|
END
|
||||||
""".format(holidays), {"employee": self.employee, "dt": dt})
|
""".format(holidays), {"employee": self.employee, "dt": dt})
|
||||||
if leave:
|
if leave:
|
||||||
lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
|
lwp = cint(leave[0][1]) and (lwp + 0.5) or (lwp + 1)
|
||||||
return lwp
|
return lwp
|
||||||
|
|
||||||
def check_existing(self):
|
def check_existing(self):
|
||||||
if not self.salary_slip_based_on_timesheet:
|
if not self.salary_slip_based_on_timesheet:
|
||||||
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
|
ret_exist = frappe.db.sql("""select name from `tabSalary Slip`
|
||||||
where start_date = %s and end_date = %s and docstatus != 2
|
where start_date = %s and end_date = %s and docstatus != 2
|
||||||
and employee = %s and name != %s""",
|
and employee = %s and name != %s""",
|
||||||
(self.start_date, self.end_date, self.employee, self.name))
|
(self.start_date, self.end_date, self.employee, self.name))
|
||||||
if ret_exist:
|
if ret_exist:
|
||||||
self.employee = ''
|
self.employee = ''
|
||||||
frappe.throw(_("Salary Slip of employee {0} already created for this period").format(self.employee))
|
frappe.throw(_("Salary Slip of employee {0} already created for this period").format(self.employee))
|
||||||
else:
|
else:
|
||||||
for data in self.timesheets:
|
for data in self.timesheets:
|
||||||
if frappe.db.get_value('Timesheet', data.time_sheet, 'status') == 'Payrolled':
|
if frappe.db.get_value('Timesheet', data.time_sheet, 'status') == 'Payrolled':
|
||||||
frappe.throw(_("Salary Slip of employee {0} already created for time sheet {1}").format(self.employee, data.time_sheet))
|
frappe.throw(_("Salary Slip of employee {0} already created for time sheet {1}").format(self.employee, data.time_sheet))
|
||||||
|
|
||||||
def sum_components(self, component_type, total_field):
|
def sum_components(self, component_type, total_field):
|
||||||
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
joining_date, relieving_date = frappe.db.get_value("Employee", self.employee,
|
||||||
["date_of_joining", "relieving_date"])
|
["date_of_joining", "relieving_date"])
|
||||||
if not relieving_date:
|
if not relieving_date:
|
||||||
relieving_date = getdate(self.end_date)
|
relieving_date = getdate(self.end_date)
|
||||||
|
|
||||||
for d in self.get(component_type):
|
for d in self.get(component_type):
|
||||||
if ((cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet) or\
|
if ((cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet) or\
|
||||||
getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date):
|
getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date):
|
||||||
|
|
||||||
d.amount = rounded((flt(d.default_amount) * flt(self.payment_days)
|
d.amount = rounded((flt(d.default_amount) * flt(self.payment_days)
|
||||||
/ cint(self.total_working_days)), self.precision("amount", component_type))
|
/ cint(self.total_working_days)), self.precision("amount", component_type))
|
||||||
elif not self.payment_days and not self.salary_slip_based_on_timesheet:
|
elif not self.payment_days and not self.salary_slip_based_on_timesheet:
|
||||||
d.amount = 0
|
d.amount = 0
|
||||||
elif not d.amount:
|
elif not d.amount:
|
||||||
d.amount = d.default_amount
|
d.amount = d.default_amount
|
||||||
self.set(total_field, self.get(total_field) + flt(d.amount))
|
self.set(total_field, self.get(total_field) + flt(d.amount))
|
||||||
|
|
||||||
def calculate_net_pay(self):
|
def calculate_net_pay(self):
|
||||||
if self.salary_structure:
|
if self.salary_structure:
|
||||||
self.calculate_component_amounts()
|
self.calculate_component_amounts()
|
||||||
|
|
||||||
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
disable_rounded_total = cint(frappe.db.get_value("Global Defaults", None, "disable_rounded_total"))
|
||||||
|
|
||||||
self.total_deduction = 0
|
self.total_deduction = 0
|
||||||
self.gross_pay = 0
|
self.gross_pay = 0
|
||||||
|
|
||||||
self.sum_components('earnings', 'gross_pay')
|
self.sum_components('earnings', 'gross_pay')
|
||||||
self.sum_components('deductions', 'total_deduction')
|
self.sum_components('deductions', 'total_deduction')
|
||||||
|
|
||||||
self.set_loan_repayment()
|
self.set_loan_repayment()
|
||||||
|
|
||||||
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
self.net_pay = flt(self.gross_pay) - (flt(self.total_deduction) + flt(self.total_loan_repayment))
|
||||||
self.rounded_total = rounded(self.net_pay,
|
self.rounded_total = rounded(self.net_pay,
|
||||||
self.precision("net_pay") if disable_rounded_total else 0)
|
self.precision("net_pay") if disable_rounded_total else 0)
|
||||||
|
|
||||||
def set_loan_repayment(self):
|
def set_loan_repayment(self):
|
||||||
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
employee_loan = frappe.db.sql("""select sum(principal_amount) as principal_amount, sum(interest_amount) as interest_amount,
|
||||||
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
sum(total_payment) as total_loan_repayment from `tabRepayment Schedule`
|
||||||
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
where payment_date between %s and %s and parent in (select name from `tabEmployee Loan`
|
||||||
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
where employee = %s and repay_from_salary = 1 and docstatus = 1)""",
|
||||||
(self.start_date, self.end_date, self.employee), as_dict=True)
|
(self.start_date, self.end_date, self.employee), as_dict=True)
|
||||||
if employee_loan:
|
if employee_loan:
|
||||||
self.principal_amount = employee_loan[0].principal_amount
|
self.principal_amount = employee_loan[0].principal_amount
|
||||||
self.interest_amount = employee_loan[0].interest_amount
|
self.interest_amount = employee_loan[0].interest_amount
|
||||||
self.total_loan_repayment = employee_loan[0].total_loan_repayment
|
self.total_loan_repayment = employee_loan[0].total_loan_repayment
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
if self.net_pay < 0:
|
if self.net_pay < 0:
|
||||||
frappe.throw(_("Net Pay cannot be less than 0"))
|
frappe.throw(_("Net Pay cannot be less than 0"))
|
||||||
else:
|
else:
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.update_status(self.name)
|
self.update_status(self.name)
|
||||||
if(frappe.db.get_single_value("HR Settings", "email_salary_slip_to_employee")):
|
if(frappe.db.get_single_value("HR Settings", "email_salary_slip_to_employee")):
|
||||||
self.email_salary_slip()
|
self.email_salary_slip()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.update_status()
|
self.update_status()
|
||||||
|
|
||||||
def email_salary_slip(self):
|
def email_salary_slip(self):
|
||||||
receiver = frappe.db.get_value("Employee", self.employee, "prefered_email")
|
receiver = frappe.db.get_value("Employee", self.employee, "prefered_email")
|
||||||
|
|
||||||
if receiver:
|
if receiver:
|
||||||
subj = 'Salary Slip - from {0} to {1}'.format(self.start_date, self.end_date)
|
subj = 'Salary Slip - from {0} to {1}'.format(self.start_date, self.end_date)
|
||||||
frappe.sendmail([receiver], subject=subj, message = _("Please see attachment"),
|
frappe.sendmail([receiver], subject=subj, message = _("Please see attachment"),
|
||||||
attachments=[frappe.attach_print(self.doctype, self.name, file_name=self.name)], reference_doctype= self.doctype, reference_name= self.name)
|
attachments=[frappe.attach_print(self.doctype, self.name, file_name=self.name)], reference_doctype= self.doctype, reference_name= self.name)
|
||||||
else:
|
else:
|
||||||
msgprint(_("{0}: Employee email not found, hence email not sent").format(self.employee_name))
|
msgprint(_("{0}: Employee email not found, hence email not sent").format(self.employee_name))
|
||||||
|
|
||||||
def update_status(self, salary_slip=None):
|
def update_status(self, salary_slip=None):
|
||||||
for data in self.timesheets:
|
for data in self.timesheets:
|
||||||
if data.time_sheet:
|
if data.time_sheet:
|
||||||
timesheet = frappe.get_doc('Timesheet', data.time_sheet)
|
timesheet = frappe.get_doc('Timesheet', data.time_sheet)
|
||||||
timesheet.salary_slip = salary_slip
|
timesheet.salary_slip = salary_slip
|
||||||
timesheet.flags.ignore_validate_update_after_submit = True
|
timesheet.flags.ignore_validate_update_after_submit = True
|
||||||
timesheet.set_status()
|
timesheet.set_status()
|
||||||
timesheet.save()
|
timesheet.save()
|
||||||
|
|
||||||
def set_status(self, status=None):
|
def set_status(self, status=None):
|
||||||
'''Get and update status'''
|
'''Get and update status'''
|
||||||
if not status:
|
if not status:
|
||||||
status = self.get_status()
|
status = self.get_status()
|
||||||
self.db_set("status", status)
|
self.db_set("status", status)
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
if self.docstatus == 0:
|
if self.docstatus == 0:
|
||||||
status = "Draft"
|
status = "Draft"
|
||||||
elif self.docstatus == 1:
|
elif self.docstatus == 1:
|
||||||
status = "Submitted"
|
status = "Submitted"
|
||||||
elif self.docstatus == 2:
|
elif self.docstatus == 2:
|
||||||
status = "Cancelled"
|
status = "Cancelled"
|
||||||
return status
|
return status
|
||||||
|
|
||||||
def unlink_ref_doc_from_salary_slip(ref_no):
|
def unlink_ref_doc_from_salary_slip(ref_no):
|
||||||
linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip`
|
linked_ss = frappe.db.sql_list("""select name from `tabSalary Slip`
|
||||||
where journal_entry=%s and docstatus < 2""", (ref_no))
|
where journal_entry=%s and docstatus < 2""", (ref_no))
|
||||||
if linked_ss:
|
if linked_ss:
|
||||||
for ss in linked_ss:
|
for ss in linked_ss:
|
||||||
ss_doc = frappe.get_doc("Salary Slip", ss)
|
ss_doc = frappe.get_doc("Salary Slip", ss)
|
||||||
frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
|
frappe.db.set_value("Salary Slip", ss_doc.name, "journal_entry", "")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user