test: leave application validations
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 369847f..d4062c7 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -37,6 +37,8 @@
class NotAnOptionalHoliday(frappe.ValidationError): pass
class InsufficientLeaveBalanceError(frappe.ValidationError):
pass
+class LeaveAcrossAllocationsError(frappe.ValidationError):
+ pass
from frappe.model.document import Document
@@ -143,7 +145,7 @@
if not (alloc_on_from_date or alloc_on_to_date):
frappe.throw(_("Application period cannot be outside leave allocation period"))
elif self.is_separate_ledger_entry_required(alloc_on_from_date, alloc_on_to_date):
- frappe.throw(_("Application period cannot be across two allocation records"))
+ frappe.throw(_("Application period cannot be across two allocation records"), exc=LeaveAcrossAllocationsError)
def get_allocation_based_on_application_dates(self):
"""Returns allocation name, from and to dates for application dates"""
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 287cb5c..7cc919e 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -20,6 +20,8 @@
from erpnext.hr.doctype.holiday_list.test_holiday_list import set_holiday_list
from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation
from erpnext.hr.doctype.leave_application.leave_application import (
+ InsufficientLeaveBalanceError,
+ LeaveAcrossAllocationsError,
LeaveDayBlockedError,
NotAnOptionalHoliday,
OverlapError,
@@ -82,8 +84,16 @@
frappe.db.delete("Attendance", {"employee": "_T-Employee-00001"})
self.holiday_list = make_holiday_list()
+ if not frappe.db.exists("Leave Type", "_Test Leave Type"):
+ frappe.get_doc(dict(
+ leave_type_name="_Test Leave Type",
+ doctype="Leave Type",
+ include_holiday=True
+ )).insert()
+
def tearDown(self):
frappe.db.rollback()
+ frappe.set_user("Administrator")
def _clear_roles(self):
frappe.db.sql("""delete from `tabHas Role` where parent in
@@ -98,6 +108,81 @@
application.to_date = "2013-01-05"
return application
+ @set_holiday_list('Salary Slip Test Holiday List', '_Test Company')
+ def test_validate_application_across_allocations(self):
+ # Test validation for application dates when negative balance is disabled
+ frappe.delete_doc_if_exists("Leave Type", "Test Leave Validation", force=1)
+ leave_type = frappe.get_doc(dict(
+ leave_type_name="Test Leave Validation",
+ doctype="Leave Type",
+ allow_negative=False
+ )).insert()
+
+ employee = get_employee()
+ date = getdate()
+ first_sunday = get_first_sunday(self.holiday_list, for_date=get_year_start(date))
+
+ leave_application = frappe.get_doc(dict(
+ doctype='Leave Application',
+ employee=employee.name,
+ leave_type=leave_type.name,
+ from_date=add_days(first_sunday, 1),
+ to_date=add_days(first_sunday, 4),
+ company="_Test Company",
+ status="Approved",
+ leave_approver = 'test@example.com'
+ ))
+ # Application period cannot be outside leave allocation period
+ self.assertRaises(frappe.ValidationError, leave_application.insert)
+
+ make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date))
+
+ leave_application = frappe.get_doc(dict(
+ doctype='Leave Application',
+ employee=employee.name,
+ leave_type=leave_type.name,
+ from_date=add_days(first_sunday, -10),
+ to_date=add_days(first_sunday, 1),
+ company="_Test Company",
+ status="Approved",
+ leave_approver = 'test@example.com'
+ ))
+
+ # Application period cannot be across two allocation records
+ self.assertRaises(LeaveAcrossAllocationsError, leave_application.insert)
+
+ @set_holiday_list('Salary Slip Test Holiday List', '_Test Company')
+ def test_insufficient_leave_balance_validation(self):
+ # CASE 1: Validation when allow negative is disabled
+ frappe.delete_doc_if_exists("Leave Type", "Test Leave Validation", force=1)
+ leave_type = frappe.get_doc(dict(
+ leave_type_name="Test Leave Validation",
+ doctype="Leave Type",
+ allow_negative=False
+ )).insert()
+
+ employee = get_employee()
+ date = getdate()
+ first_sunday = get_first_sunday(self.holiday_list, for_date=get_year_start(date))
+
+ # allocate 2 leaves, apply for more
+ make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date), leaves=2)
+ leave_application = frappe.get_doc(dict(
+ doctype='Leave Application',
+ employee=employee.name,
+ leave_type=leave_type.name,
+ from_date=add_days(first_sunday, 1),
+ to_date=add_days(first_sunday, 3),
+ company="_Test Company",
+ status="Approved",
+ leave_approver = 'test@example.com'
+ ))
+ self.assertRaises(InsufficientLeaveBalanceError, leave_application.insert)
+
+ # CASE 2: Allows creating application with a warning message when allow negative is enabled
+ frappe.db.set_value("Leave Type", "Test Leave Validation", "allow_negative", True)
+ make_leave_application(employee.name, add_days(first_sunday, 1), add_days(first_sunday, 3), leave_type.name)
+
def test_overwrite_attendance(self):
'''check attendance is automatically created on leave approval'''
make_allocation_record()
@@ -562,7 +647,14 @@
# test to not consider current leave in leave balance while submitting
def test_current_leave_on_submit(self):
employee = get_employee()
- leave_type = 'Sick leave'
+
+ leave_type = 'Sick Leave'
+ if not frappe.db.exists('Leave Type', leave_type):
+ frappe.get_doc(dict(
+ leave_type_name=leave_type,
+ doctype='Leave Type'
+ )).insert()
+
allocation = frappe.get_doc(dict(
doctype = 'Leave Allocation',
employee = employee.name,