[salary slip] total no. of working days calculation [issue] webnotes/erpnext#285
This commit is contained in:
parent
6cd2ed88bb
commit
e79d57ca19
@ -141,8 +141,9 @@ class AccountsController(TransactionBase):
|
||||
|
||||
def calculate_taxes_and_totals(self):
|
||||
# validate conversion rate
|
||||
if not self.doc.currency:
|
||||
self.doc.currency = get_company_currency(self.doc.company)
|
||||
company_currency = get_company_currency(self.doc.company)
|
||||
if not self.doc.currency or self.doc.currency == company_currency:
|
||||
self.doc.currency = company_currency
|
||||
self.doc.conversion_rate = 1.0
|
||||
else:
|
||||
validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
|
||||
|
10
hr/doctype/deduction_type/test_deduction_type.py
Normal file
10
hr/doctype/deduction_type/test_deduction_type.py
Normal file
@ -0,0 +1,10 @@
|
||||
test_records = [
|
||||
[{
|
||||
"doctype": "Deduction Type",
|
||||
"deduction_name": "_Test Professional Tax"
|
||||
}],
|
||||
[{
|
||||
"doctype": "Deduction Type",
|
||||
"deduction_name": "_Test TDS"
|
||||
}]
|
||||
]
|
12
hr/doctype/earning_type/test_earning_type.py
Normal file
12
hr/doctype/earning_type/test_earning_type.py
Normal file
@ -0,0 +1,12 @@
|
||||
test_records = [
|
||||
[{
|
||||
"doctype": "Earning Type",
|
||||
"earning_name": "_Test Basic Salary",
|
||||
"taxable": "Yes"
|
||||
}],
|
||||
[{
|
||||
"doctype": "Earning Type",
|
||||
"earning_name": "_Test Allowance",
|
||||
"taxable": "Yes"
|
||||
}]
|
||||
]
|
@ -1,7 +1,8 @@
|
||||
test_records = [[{
|
||||
"doctype": "Holiday List",
|
||||
"holiday_list_name": "_Test Holiday List",
|
||||
"fiscal_year": "_Test Fiscal Year 2013"
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
"is_default": 1
|
||||
}, {
|
||||
"doctype": "Holiday",
|
||||
"parent": "_Test Holiday List",
|
||||
|
0
hr/doctype/hr_settings/__init__.py
Normal file
0
hr/doctype/hr_settings/__init__.py
Normal file
8
hr/doctype/hr_settings/hr_settings.py
Normal file
8
hr/doctype/hr_settings/hr_settings.py
Normal file
@ -0,0 +1,8 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
class DocType:
|
||||
def __init__(self, d, dl):
|
||||
self.doc, self.doclist = d, dl
|
59
hr/doctype/hr_settings/hr_settings.txt
Normal file
59
hr/doctype/hr_settings/hr_settings.txt
Normal file
@ -0,0 +1,59 @@
|
||||
[
|
||||
{
|
||||
"creation": "2013-08-02 13:45:23",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-08-02 14:22:26",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"icon": "icon-cog",
|
||||
"issingle": 1,
|
||||
"module": "HR",
|
||||
"name": "__common__"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"name": "__common__",
|
||||
"parent": "HR Settings",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"name": "__common__",
|
||||
"parent": "HR Settings",
|
||||
"parentfield": "permissions",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"name": "HR Settings"
|
||||
},
|
||||
{
|
||||
"description": "Employee record is created using selected field. ",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "emp_created_by",
|
||||
"fieldtype": "Select",
|
||||
"label": "Employee Records to be created by",
|
||||
"options": "Naming Series\nEmployee Number"
|
||||
},
|
||||
{
|
||||
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "include_holidays_in_total_working_days",
|
||||
"fieldtype": "Check",
|
||||
"label": "Include holidays in Total no. of Working Days"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm"
|
||||
}
|
||||
]
|
@ -236,5 +236,15 @@ test_records = [
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
"employee": "_T-Employee-0002",
|
||||
"company": "_Test Company"
|
||||
}],
|
||||
[{
|
||||
"doctype": "Leave Application",
|
||||
"leave_type": "_Test Leave Type LWP",
|
||||
"from_date": "2013-01-02",
|
||||
"to_date": "2013-01-02",
|
||||
"posting_date": "2013-01-02",
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
"employee": "_T-Employee-0001",
|
||||
"company": "_Test Company",
|
||||
}]
|
||||
]
|
||||
|
@ -2,5 +2,10 @@ test_records = [
|
||||
[{
|
||||
"leave_type_name": "_Test Leave Type",
|
||||
"doctype": "Leave Type"
|
||||
}],
|
||||
[{
|
||||
"leave_type_name": "_Test Leave Type LWP",
|
||||
"doctype": "Leave Type",
|
||||
"is_lwp": 1
|
||||
}]
|
||||
]
|
@ -112,26 +112,16 @@ class DocType:
|
||||
if not sql("""select name from `tabSalary Slip`
|
||||
where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s
|
||||
""", (emp[0], self.doc.month, self.doc.fiscal_year, self.doc.company)):
|
||||
ss = Document('Salary Slip')
|
||||
ss.fiscal_year = self.doc.fiscal_year
|
||||
ss.employee = emp[0]
|
||||
ss.month = self.doc.month
|
||||
ss.email_check = self.doc.send_email
|
||||
ss.company = self.doc.company
|
||||
ss.save(1)
|
||||
|
||||
ss_obj = get_obj('Salary Slip', ss.name, with_children=1)
|
||||
ss_obj.get_emp_and_leave_details()
|
||||
ss_obj.calculate_net_pay()
|
||||
ss_obj.validate()
|
||||
ss_obj.doc.save()
|
||||
|
||||
for d in getlist(ss_obj.doclist, 'earning_details'):
|
||||
d.save()
|
||||
for d in getlist(ss_obj.doclist, 'deduction_details'):
|
||||
d.save()
|
||||
|
||||
ss_list.append(ss.name)
|
||||
ss = webnotes.bean({
|
||||
"doctype": "Salary Slip",
|
||||
"fiscal_year": self.doc.fiscal_year,
|
||||
"employee": emp[0],
|
||||
"month": self.doc.month,
|
||||
"email_check": self.doc.send_email,
|
||||
"company": self.doc.company,
|
||||
})
|
||||
ss.insert()
|
||||
ss_list.append(ss.doc.name)
|
||||
|
||||
return self.create_log(ss_list)
|
||||
|
||||
|
@ -61,7 +61,7 @@ class DocType(TransactionBase):
|
||||
["bank_name", "bank_ac_no", "esic_card_no", "pf_number"], as_dict=1)
|
||||
if emp:
|
||||
self.doc.bank_name = emp.bank_name
|
||||
self.doc.bank_ac_no = emp.bank_ac_no
|
||||
self.doc.bank_account_no = emp.bank_ac_no
|
||||
self.doc.esic_no = emp.esic_card_no
|
||||
self.doc.pf_no = emp.pf_number
|
||||
|
||||
@ -72,9 +72,17 @@ class DocType(TransactionBase):
|
||||
self.doc.month = "%02d" % getdate(nowdate()).month
|
||||
|
||||
m = get_obj('Salary Manager').get_month_details(self.doc.fiscal_year, self.doc.month)
|
||||
holidays = self.get_holidays_for_employee(m)
|
||||
|
||||
if not cint(webnotes.conn.get_value("HR Settings", "HR Settings",
|
||||
"include_holidays_in_total_working_days")):
|
||||
m["month_days"] -= len(holidays)
|
||||
if m["month_days"] < 0:
|
||||
msgprint(_("Bummer! There are more holidays than working days this month."),
|
||||
raise_exception=True)
|
||||
|
||||
if not lwp:
|
||||
lwp = self.calculate_lwp(m)
|
||||
lwp = self.calculate_lwp(holidays, m)
|
||||
self.doc.total_days_in_month = m['month_days']
|
||||
self.doc.leave_without_pay = lwp
|
||||
payment_days = flt(self.get_payment_days(m)) - flt(lwp)
|
||||
@ -104,10 +112,7 @@ class DocType(TransactionBase):
|
||||
|
||||
return payment_days
|
||||
|
||||
|
||||
|
||||
|
||||
def calculate_lwp(self, m):
|
||||
def get_holidays_for_employee(self, m):
|
||||
holidays = sql("""select t1.holiday_date
|
||||
from `tabHoliday` t1, tabEmployee t2
|
||||
where t1.parent = t2.holiday_list and t2.name = %s
|
||||
@ -117,8 +122,13 @@ class DocType(TransactionBase):
|
||||
holidays = sql("""select t1.holiday_date
|
||||
from `tabHoliday` t1, `tabHoliday List` t2
|
||||
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
|
||||
and t2.fiscal_year = %s""", self.doc.fiscal_year)
|
||||
and t2.fiscal_year = %s
|
||||
and t1.holiday_date between %s and %s""", (self.doc.fiscal_year,
|
||||
m['month_start_date'], m['month_end_date']))
|
||||
holidays = [cstr(i[0]) for i in holidays]
|
||||
return holidays
|
||||
|
||||
def calculate_lwp(self, holidays, m):
|
||||
lwp = 0
|
||||
for d in range(m['month_days']):
|
||||
dt = add_days(cstr(m['month_start_date']), d)
|
||||
@ -133,7 +143,7 @@ class DocType(TransactionBase):
|
||||
and %s between from_date and to_date
|
||||
""", (self.doc.employee, dt))
|
||||
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
|
||||
|
||||
def check_existing(self):
|
||||
@ -150,17 +160,29 @@ class DocType(TransactionBase):
|
||||
def validate(self):
|
||||
from webnotes.utils import money_in_words
|
||||
self.check_existing()
|
||||
|
||||
if not (len(self.doclist.get({"parentfield": "earning_details"})) or
|
||||
len(self.doclist.get({"parentfield": "deduction_details"}))):
|
||||
self.get_emp_and_leave_details()
|
||||
else:
|
||||
self.get_leave_details(self.doc.leave_without_pay)
|
||||
|
||||
if not self.doc.net_pay:
|
||||
self.calculate_net_pay()
|
||||
|
||||
company_currency = get_company_currency(self.doc.company)
|
||||
self.doc.total_in_words = money_in_words(self.doc.rounded_total, company_currency)
|
||||
|
||||
def calculate_earning_total(self):
|
||||
self.doc.gross_pay = flt(self.doc.arrear_amount) + flt(self.doc.leave_encashment_amount)
|
||||
for d in getlist(self.doclist, 'earning_details'):
|
||||
for d in self.doclist.get({"parentfield": "earning_details"}):
|
||||
if cint(d.e_depends_on_lwp) == 1:
|
||||
d.e_modified_amount = round(flt(d.e_amount) * flt(self.doc.payment_days)
|
||||
/ cint(self.doc.total_days_in_month), 2)
|
||||
elif not self.doc.payment_days:
|
||||
d.e_modified_amount = 0
|
||||
else:
|
||||
d.e_modified_amount = d.e_amount
|
||||
self.doc.gross_pay += flt(d.e_modified_amount)
|
||||
|
||||
def calculate_ded_total(self):
|
||||
@ -171,6 +193,8 @@ class DocType(TransactionBase):
|
||||
/ cint(self.doc.total_days_in_month), 2)
|
||||
elif not self.doc.payment_days:
|
||||
d.d_modified_amount = 0
|
||||
else:
|
||||
d.d_modified_amount = d.d_amount
|
||||
|
||||
self.doc.total_deduction += flt(d.d_modified_amount)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-01-10 16:34:15",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-05 14:53:44",
|
||||
"modified": "2013-08-02 19:23:13",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -190,7 +190,7 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "total_days_in_month",
|
||||
"fieldtype": "Data",
|
||||
"label": "Total days in month",
|
||||
"label": "Total Working Days In The Month",
|
||||
"oldfieldname": "total_days_in_month",
|
||||
"oldfieldtype": "Int",
|
||||
"read_only": 1,
|
||||
@ -208,7 +208,7 @@
|
||||
"doctype": "DocField",
|
||||
"fieldname": "payment_days",
|
||||
"fieldtype": "Float",
|
||||
"label": "Payment days",
|
||||
"label": "Payment Days",
|
||||
"oldfieldname": "payment_days",
|
||||
"oldfieldtype": "Float",
|
||||
"read_only": 1,
|
||||
|
85
hr/doctype/salary_slip/test_salary_slip.py
Normal file
85
hr/doctype/salary_slip/test_salary_slip.py
Normal file
@ -0,0 +1,85 @@
|
||||
import webnotes
|
||||
import unittest
|
||||
|
||||
class TestSalarySlip(unittest.TestCase):
|
||||
def setUp(self):
|
||||
webnotes.conn.sql("""delete from `tabLeave Application`""")
|
||||
webnotes.conn.sql("""delete from `tabSalary Slip`""")
|
||||
from hr.doctype.leave_application.test_leave_application import test_records as leave_applications
|
||||
la = webnotes.bean(copy=leave_applications[4])
|
||||
la.insert()
|
||||
la.doc.status = "Approved"
|
||||
la.submit()
|
||||
|
||||
def tearDown(self):
|
||||
webnotes.conn.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 0)
|
||||
|
||||
def test_salary_slip_with_holidays_included(self):
|
||||
webnotes.conn.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 1)
|
||||
ss = webnotes.bean(copy=test_records[0])
|
||||
ss.insert()
|
||||
self.assertEquals(ss.doc.total_days_in_month, 31)
|
||||
self.assertEquals(ss.doc.payment_days, 30)
|
||||
self.assertEquals(ss.doclist[1].e_modified_amount, 14516.13)
|
||||
self.assertEquals(ss.doclist[2].e_modified_amount, 500)
|
||||
self.assertEquals(ss.doclist[3].d_modified_amount, 100)
|
||||
self.assertEquals(ss.doclist[4].d_modified_amount, 48.39)
|
||||
self.assertEquals(ss.doc.gross_pay, 15016.13)
|
||||
self.assertEquals(ss.doc.net_pay, 14867.74)
|
||||
|
||||
def test_salary_slip_with_holidays_excluded(self):
|
||||
ss = webnotes.bean(copy=test_records[0])
|
||||
ss.insert()
|
||||
self.assertEquals(ss.doc.total_days_in_month, 30)
|
||||
self.assertEquals(ss.doc.payment_days, 29)
|
||||
self.assertEquals(ss.doclist[1].e_modified_amount, 14500)
|
||||
self.assertEquals(ss.doclist[2].e_modified_amount, 500)
|
||||
self.assertEquals(ss.doclist[3].d_modified_amount, 100)
|
||||
self.assertEquals(ss.doclist[4].d_modified_amount, 48.33)
|
||||
self.assertEquals(ss.doc.gross_pay, 15000)
|
||||
self.assertEquals(ss.doc.net_pay, 14851.67)
|
||||
|
||||
test_dependencies = ["Leave Application"]
|
||||
|
||||
test_records = [
|
||||
[
|
||||
{
|
||||
"doctype": "Salary Slip",
|
||||
"employee": "_T-Employee-0001",
|
||||
"employee_name": "_Test Employee",
|
||||
"company": "_Test Company",
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
"month": "01",
|
||||
"total_days_in_month": 31,
|
||||
"payment_days": 31
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Slip Earning",
|
||||
"parentfield": "earning_details",
|
||||
"e_type": "_Test Basic Salary",
|
||||
"e_amount": 15000,
|
||||
"e_depends_on_lwp": 1
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Slip Earning",
|
||||
"parentfield": "earning_details",
|
||||
"e_type": "_Test Allowance",
|
||||
"e_amount": 500,
|
||||
"e_depends_on_lwp": 0
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Slip Deduction",
|
||||
"parentfield": "deduction_details",
|
||||
"d_type": "_Test Professional Tax",
|
||||
"d_amount": 100,
|
||||
"d_depends_on_lwp": 0
|
||||
},
|
||||
{
|
||||
"doctype": "Salary Slip Deduction",
|
||||
"parentfield": "deduction_details",
|
||||
"d_type": "_Test TDS",
|
||||
"d_amount": 50,
|
||||
"d_depends_on_lwp": 1
|
||||
},
|
||||
]
|
||||
]
|
@ -161,6 +161,18 @@ wn.module_page["HR"] = [
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: wn._("Setup"),
|
||||
icon: "icon-cog",
|
||||
items: [
|
||||
{
|
||||
"label": wn._("HR Settings"),
|
||||
"route": "Form/HR Settings",
|
||||
"doctype":"HR Settings",
|
||||
"description": "Settings for HR Module"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: wn._("Reports"),
|
||||
right: true,
|
||||
|
0
patches/august_2013/__init__.py
Normal file
0
patches/august_2013/__init__.py
Normal file
16
patches/august_2013/p01_hr_settings.py
Normal file
16
patches/august_2013/p01_hr_settings.py
Normal file
@ -0,0 +1,16 @@
|
||||
import webnotes
|
||||
|
||||
def execute():
|
||||
webnotes.reload_doc("hr", "doctype", "hr_settings")
|
||||
webnotes.reload_doc("setup", "doctype", "global_defaults")
|
||||
|
||||
hr = webnotes.bean("HR Settings", "HR Settings")
|
||||
hr.doc.emp_created_by = webnotes.conn.get_value("Global Defaults", "Global Defaults", "emp_created_by")
|
||||
|
||||
if webnotes.conn.sql("""select name from `tabSalary Slip` where docstatus=1 limit 1"""):
|
||||
hr.doc.include_holidays_in_total_working_days = 1
|
||||
|
||||
hr.save()
|
||||
|
||||
webnotes.conn.sql("""delete from `tabSingles` where doctype = 'Global Defaults'
|
||||
and field = 'emp_created_by'""")
|
@ -264,4 +264,5 @@ patch_list = [
|
||||
"patches.july_2013.p10_change_partner_user_to_website_user",
|
||||
"patches.july_2013.p11_update_price_list_currency",
|
||||
"execute:webnotes.bean('Selling Settings').save() #2013-07-29",
|
||||
"patches.august_2013.p01_hr_settings",
|
||||
]
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-05-02 17:53:24",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-15 15:03:01",
|
||||
"modified": "2013-08-02 13:45:12",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -181,15 +181,6 @@
|
||||
"label": "HR",
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"description": "Employee record is created using selected field. ",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "emp_created_by",
|
||||
"fieldtype": "Select",
|
||||
"label": "Employee Records to be created by ",
|
||||
"options": "Naming Series\nEmployee Number",
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user