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