From 697150f339e47293cde109724fd983fc2ae2b23d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 24 Feb 2017 18:53:23 +0530 Subject: [PATCH] Leave application overlap validation for half day and test cases --- .../leave_application/leave_application.py | 34 +++++++---- .../test_leave_application.py | 59 +++++++++++++++++-- ...ar_leave_encashment_as_salary_component.py | 7 ++- 3 files changed, 79 insertions(+), 21 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index d869e0abe8..c53c2309f4 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -64,8 +64,11 @@ class LeaveApplication(Document): if self.from_date and self.to_date and (getdate(self.to_date) < getdate(self.from_date)): frappe.throw(_("To date cannot be before from date")) - if self.half_day and (getdate(self.half_day_date) < getdate(self.from_date) or (getdate(self.half_day_date) > getdate(self.to_date))): - frappe.throw(_("Half Day Date should be between From Date and To Date")) + if self.half_day and self.half_day_date \ + and (getdate(self.half_day_date) < getdate(self.from_date) + or getdate(self.half_day_date) > getdate(self.to_date)): + + frappe.throw(_("Half Day Date should be between From Date and To Date")) if not is_lwp(self.leave_type): self.validate_dates_acorss_allocation() @@ -154,7 +157,9 @@ class LeaveApplication(Document): # hack! if name is null, it could cause problems with != self.name = "New Leave Application" - for d in frappe.db.sql("""select name, leave_type, posting_date, from_date, to_date, total_leave_days + for d in frappe.db.sql(""" + select + name, leave_type, posting_date, from_date, to_date, total_leave_days, half_day_date from `tabLeave Application` where employee = %(employee)s and docstatus < 2 and status in ("Open", "Approved") and to_date >= %(from_date)s and from_date <= %(to_date)s @@ -164,10 +169,14 @@ class LeaveApplication(Document): "to_date": self.to_date, "name": self.name }, as_dict = 1): - - if d['total_leave_days']==0.5 and cint(self.half_day)==1: - sum_leave_days = self.get_total_leaves_on_half_day() - if sum_leave_days==1: + + if cint(self.half_day)==1 and getdate(self.half_day_date) == getdate(d.half_day_date) and ( + flt(self.total_leave_days)==0.5 + or getdate(self.from_date) == getdate(d.to_date) + or getdate(self.to_date) == getdate(d.from_date)): + + total_leaves_on_half_day = self.get_total_leaves_on_half_day() + if total_leaves_on_half_day >= 1: self.throw_overlap_error(d) else: self.throw_overlap_error(d) @@ -179,18 +188,19 @@ class LeaveApplication(Document): frappe.throw(msg, OverlapError) def get_total_leaves_on_half_day(self): - return frappe.db.sql("""select sum(total_leave_days) from `tabLeave Application` + leave_count_on_half_day_date = frappe.db.sql("""select count(name) from `tabLeave Application` where employee = %(employee)s and docstatus < 2 and status in ("Open", "Approved") - and from_date = %(from_date)s - and to_date = %(to_date)s + and half_day = 1 + and half_day_date = %(half_day_date)s and name != %(name)s""", { "employee": self.employee, - "from_date": self.from_date, - "to_date": self.to_date, + "half_day_date": self.half_day_date, "name": self.name })[0][0] + + return leave_count_on_half_day_date * 0.5 def validate_max_days(self): max_days = frappe.db.get_value("Leave Type", self.leave_type, "max_days_allowed") diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py index 83fdd58509..f7a996b50b 100644 --- a/erpnext/hr/doctype/leave_application/test_leave_application.py +++ b/erpnext/hr/doctype/leave_application/test_leave_application.py @@ -134,7 +134,7 @@ class TestLeaveApplication(unittest.TestCase): application.leave_approver = "test2@example.com" self.assertRaises(OverlapError, application.insert) - def test_overlap_with_half_day(self): + def test_overlap_with_half_day_1(self): self._clear_roles() self._clear_applications() @@ -146,25 +146,33 @@ class TestLeaveApplication(unittest.TestCase): make_allocation_record() - # allow second half-day on the same day if available + # leave from 1-5, half day on 3rd application = self.get_application(_test_records[0]) application.leave_approver = "test2@example.com" application.half_day = 1 + application.half_day_date = "2013-01-03" application.insert() - # allow second half-day on the same day if available + # Apply again for a half day leave on 3rd application = self.get_application(_test_records[0]) application.leave_approver = "test2@example.com" + application.from_date = "2013-01-03" + application.to_date = "2013-01-03" application.half_day = 1 + application.half_day_date = "2013-01-03" application.insert() + # Apply again for a half day leave on 3rd application = self.get_application(_test_records[0]) application.leave_approver = "test2@example.com" + application.from_date = "2013-01-03" + application.to_date = "2013-01-03" application.half_day = 1 + application.half_day_date = "2013-01-03" self.assertRaises(OverlapError, application.insert) - def test_overlap_with_half_day_not_applicable(self): + def test_overlap_with_half_day_2(self): self._clear_roles() self._clear_applications() @@ -176,17 +184,56 @@ class TestLeaveApplication(unittest.TestCase): make_allocation_record() - # allow second half-day on the same day if available + # leave from 1-5, no half day application = self.get_application(_test_records[0]) application.leave_approver = "test2@example.com" application.insert() - # allow second half-day on the same day if available + # Apply again for a half day leave on 1st application = self.get_application(_test_records[0]) application.leave_approver = "test2@example.com" application.half_day = 1 + application.half_day_date = application.from_date self.assertRaises(OverlapError, application.insert) + + def test_overlap_with_half_day_3(self): + self._clear_roles() + self._clear_applications() + + from frappe.utils.user import add_role + add_role("test@example.com", "Employee") + add_role("test2@example.com", "Leave Approver") + + frappe.set_user("test@example.com") + + make_allocation_record() + + # leave from 1-5, half day on 5th + application = self.get_application(_test_records[0]) + application.leave_approver = "test2@example.com" + application.half_day = 1 + application.half_day_date = "2013-01-05" + application.insert() + + # Apply leave from 4-7, half day on 5th + application = self.get_application(_test_records[0]) + application.leave_approver = "test2@example.com" + application.from_date = "2013-01-04" + application.to_date = "2013-01-07" + application.half_day = 1 + application.half_day_date = "2013-01-05" + + self.assertRaises(OverlapError, application.insert) + + # Apply leave from 5-7, half day on 5th + application = self.get_application(_test_records[0]) + application.leave_approver = "test2@example.com" + application.from_date = "2013-01-05" + application.to_date = "2013-01-07" + application.half_day = 1 + application.half_day_date = "2013-01-05" + application.insert() def test_global_block_list(self): self._clear_roles() diff --git a/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py b/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py index 0e5dab3eb0..13a2bb8d5a 100644 --- a/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py +++ b/erpnext/patches/v7_2/arrear_leave_encashment_as_salary_component.py @@ -2,13 +2,14 @@ import frappe def execute(): frappe.reload_doctype('Salary Slip', 'Salary Component') - salary_components = ['Arrear', 'Leave Encashment'] - for salary_component in salary_components: + salary_components = [['Arrear', "ARR"], ['Leave Encashment', 'LENC']] + for salary_component, salary_abbr in salary_components: if not frappe.db.exists('Salary Component', salary_component): sal_comp = frappe.get_doc({ "doctype": "Salary Component", "salary_component": salary_component, - "type": "Earning" + "type": "Earning", + "salary_component_abbr": salary_abbr }).insert() salary_slips = frappe.db.sql("""select name, arrear_amount, leave_encashment_amount from `tabSalary Slip`