Merge branch 'enterprise_sprint' of https://github.com/frappe/erpnext into enterprise_sprint
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index b33bd54..23514e1 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -5,8 +5,8 @@
import frappe
from frappe import _
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
- comma_or, get_fullname
-from erpnext.hr.utils import set_employee_name
+ comma_or, get_fullname, add_days
+from erpnext.hr.utils import set_employee_name, get_leave_period
from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -15,6 +15,7 @@
class InvalidLeaveApproverError(frappe.ValidationError): pass
class LeaveApproverIdentityError(frappe.ValidationError): pass
class AttendanceAlreadyMarkedError(frappe.ValidationError): pass
+class NotAnOptionalHoliday(frappe.ValidationError): pass
from frappe.model.document import Document
class LeaveApplication(Document):
@@ -31,6 +32,8 @@
self.validate_block_days()
self.validate_salary_processed_days()
self.validate_attendance()
+ if frappe.db.get_value("Leave Type", self.leave_type, 'is_optional_leave'):
+ self.validate_optional_leave()
def on_update(self):
if self.status == "Open" and self.docstatus < 1:
@@ -207,6 +210,19 @@
frappe.throw(_("Attendance for employee {0} is already marked for this day").format(self.employee),
AttendanceAlreadyMarkedError)
+ def validate_optional_leave(self):
+ leave_period = get_leave_period(self.from_date, self.to_date, self.company)
+ if not leave_period:
+ frappe.throw(_("Cannot find active Leave Period"))
+ optional_holiday_list = frappe.db.get_value("Leave Period", leave_period[0]["name"], "optional_holiday_list")
+ if not optional_holiday_list:
+ frappe.throw(_("Optional Holiday List not set for leave period {0}").format(leave_period[0]["name"]))
+ day = getdate(self.from_date)
+ while day <= getdate(self.to_date):
+ if not frappe.db.exists({"doctype": "Holiday", "parent": optional_holiday_list, "holiday_date": day}):
+ frappe.throw(_("{0} is not in Optional Holiday List").format(formatdate(day)), NotAnOptionalHoliday)
+ day = add_days(day, 1)
+
def notify_employee(self):
employee = frappe.get_doc("Employee", self.employee)
if not employee.user_id:
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 424da90..e71357c 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -5,8 +5,9 @@
import frappe
import unittest
-from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError
+from erpnext.hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError, NotAnOptionalHoliday, get_leave_balance_on
from frappe.permissions import clear_user_permissions_for_doctype
+from frappe.utils import add_days, nowdate
test_dependencies = ["Leave Allocation", "Leave Block List"]
@@ -225,55 +226,54 @@
frappe.db.set_value("Leave Block List", "_Test Leave Block List",
"applies_to_all_departments", 0)
-
+
def test_optional_leave(self):
- ''''''
leave_period = get_leave_period()
- today = get_today()
-
+ today = nowdate()
+ from datetime import date
holiday_list = frappe.get_doc(dict(
doctype = 'Holiday List',
- name = 'test holiday list for optional holiday',
- from_date = year_start_date(),
- to_date = year_end_date(),
+ holiday_list_name = 'test holiday list for optional holiday',
+ from_date = date(date.today().year, 1, 1),
+ to_date = date(date.today().year, 12, 31),
holidays = [
dict(holiday_date = today, description = 'test')
]
- ))
+ )).insert()
employee = get_employee()
-
- frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
-
+
+ frappe.db.set_value('Leave Period', leave_period.name, 'optional_holiday_list', holiday_list.name)
+
leave_type = frappe.get_doc(dict(
leave_type_name = 'Test Optional Type',
doctype = 'Leave Type',
- is_optional_leave = 1,
- holiday_list = holiday_list
+ is_optional_leave = 1
)).insert()
-
+
allocate_leaves(employee, leave_period, leave_type.name, 10)
-
- date = get_today() - 1
-
+
+ date = add_days(today, - 1)
+
leave_application = frappe.get_doc(dict(
doctype = 'Leave Application',
- employee = employee,
+ employee = employee.name,
leave_type = leave_type.name,
from_date = date,
to_date = date,
))
-
+
# can only apply on optional holidays
self.assertTrue(NotAnOptionalHoliday, leave_application.insert)
-
+
leave_application.from_date = today
leave_application.to_date = today
+ leave_application.status = "Approved"
leave_application.insert()
leave_application.submit()
-
+
# check leave balance is reduced
- self.assertEqual(get_leave_balance(employee, leave_period, leave_type.name), 9)
-
+ self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, today), 9)
+
def test_leaves_allowed(self):
# TODO: test cannot allocate more than max leaves
pass
@@ -285,7 +285,7 @@
def test_max_continuous_leaves(self):
# TODO: test cannot take continuous leaves more than
pass
-
+
def test_earned_leave(self):
leave_period = get_leave_period()
employee = get_employee()
@@ -297,14 +297,14 @@
earned_leave_frequency = 'Monthly',
rounding = 0.5
)).insert()
-
+
allocate_leaves(employee, leave_period, leave_type.name, 0, eligible_leaves = 12)
-
+
# this method will be called by scheduler
allocate_earned_leaves(leave_type.name, leave_period, as_on = half_of_leave_period)
-
+
self.assertEqual(get_leave_balance(employee, leave_period, leave_type.name), 6)
-
+
def make_allocation_record(employee=None, leave_type=None):
frappe.db.sql("delete from `tabLeave Allocation`")
@@ -319,4 +319,4 @@
})
allocation.insert(ignore_permissions=True)
- allocation.submit()
\ No newline at end of file
+ allocation.submit()
diff --git a/erpnext/hr/doctype/leave_period/leave_period.json b/erpnext/hr/doctype/leave_period/leave_period.json
index 946ceec..516d52d 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.json
+++ b/erpnext/hr/doctype/leave_period/leave_period.json
@@ -41,7 +41,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -72,7 +71,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -102,7 +100,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -134,7 +131,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -165,7 +161,37 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "optional_holiday_list",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Holiday List for Optional Leave",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Holiday List",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
"unique": 0
},
{
@@ -196,7 +222,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -227,7 +252,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -259,7 +283,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -291,7 +314,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -323,7 +345,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -355,7 +376,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -386,7 +406,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -416,7 +435,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -447,7 +465,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -461,7 +478,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-14 13:29:57.066314",
+ "modified": "2018-05-04 18:25:06.719932",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Period",
@@ -470,6 +487,7 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -489,6 +507,7 @@
},
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -508,6 +527,7 @@
},
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index 1d1aef20..aad7e7b 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -41,7 +41,6 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -73,7 +72,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -104,7 +102,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -136,7 +133,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -166,7 +162,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -198,7 +193,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -228,7 +222,36 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_optional_leave",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Is Optional Leave",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
"unique": 0
},
{
@@ -258,7 +281,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -288,7 +310,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -319,7 +340,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -350,7 +370,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -382,7 +401,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -413,7 +431,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -445,7 +462,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -478,102 +494,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
- "fieldname": "section_break_13",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Optional Leave",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "is_optional_leave",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Is Optional Leave",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "is_optional_leave",
- "fieldname": "holiday_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Holiday List",
- "length": 0,
- "no_copy": 0,
- "options": "Holiday List",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -604,7 +524,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -635,7 +554,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -668,7 +586,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
},
{
@@ -701,7 +618,6 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
"unique": 0
}
],
@@ -716,7 +632,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-04-14 14:36:46.824289",
+ "modified": "2018-05-03 19:42:23.852331",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
@@ -724,6 +640,7 @@
"permissions": [
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -743,6 +660,7 @@
},
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@@ -762,6 +680,7 @@
},
{
"amend": 0,
+ "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,