Merge branch 'enterprise_sprint' of https://github.com/frappe/erpnext into enterprise_sprint

This commit is contained in:
Nabin Hait 2018-05-07 16:13:33 +05:30
commit b7613af73c
4 changed files with 117 additions and 162 deletions

View File

@ -5,8 +5,8 @@ from __future__ import unicode_literals
import frappe import frappe
from frappe import _ from frappe import _
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \ from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
comma_or, get_fullname comma_or, get_fullname, add_days
from erpnext.hr.utils import set_employee_name 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.leave_block_list.leave_block_list import get_applicable_block_dates
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@ -15,6 +15,7 @@ class OverlapError(frappe.ValidationError): pass
class InvalidLeaveApproverError(frappe.ValidationError): pass class InvalidLeaveApproverError(frappe.ValidationError): pass
class LeaveApproverIdentityError(frappe.ValidationError): pass class LeaveApproverIdentityError(frappe.ValidationError): pass
class AttendanceAlreadyMarkedError(frappe.ValidationError): pass class AttendanceAlreadyMarkedError(frappe.ValidationError): pass
class NotAnOptionalHoliday(frappe.ValidationError): pass
from frappe.model.document import Document from frappe.model.document import Document
class LeaveApplication(Document): class LeaveApplication(Document):
@ -31,6 +32,8 @@ class LeaveApplication(Document):
self.validate_block_days() self.validate_block_days()
self.validate_salary_processed_days() self.validate_salary_processed_days()
self.validate_attendance() self.validate_attendance()
if frappe.db.get_value("Leave Type", self.leave_type, 'is_optional_leave'):
self.validate_optional_leave()
def on_update(self): def on_update(self):
if self.status == "Open" and self.docstatus < 1: if self.status == "Open" and self.docstatus < 1:
@ -207,6 +210,19 @@ class LeaveApplication(Document):
frappe.throw(_("Attendance for employee {0} is already marked for this day").format(self.employee), frappe.throw(_("Attendance for employee {0} is already marked for this day").format(self.employee),
AttendanceAlreadyMarkedError) 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): def notify_employee(self):
employee = frappe.get_doc("Employee", self.employee) employee = frappe.get_doc("Employee", self.employee)
if not employee.user_id: if not employee.user_id:

View File

@ -5,8 +5,9 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest 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.permissions import clear_user_permissions_for_doctype
from frappe.utils import add_days, nowdate
test_dependencies = ["Leave Allocation", "Leave Block List"] test_dependencies = ["Leave Allocation", "Leave Block List"]
@ -225,55 +226,54 @@ class TestLeaveApplication(unittest.TestCase):
frappe.db.set_value("Leave Block List", "_Test Leave Block List", frappe.db.set_value("Leave Block List", "_Test Leave Block List",
"applies_to_all_departments", 0) "applies_to_all_departments", 0)
def test_optional_leave(self): def test_optional_leave(self):
''''''
leave_period = get_leave_period() leave_period = get_leave_period()
today = get_today() today = nowdate()
from datetime import date
holiday_list = frappe.get_doc(dict( holiday_list = frappe.get_doc(dict(
doctype = 'Holiday List', doctype = 'Holiday List',
name = 'test holiday list for optional holiday', holiday_list_name = 'test holiday list for optional holiday',
from_date = year_start_date(), from_date = date(date.today().year, 1, 1),
to_date = year_end_date(), to_date = date(date.today().year, 12, 31),
holidays = [ holidays = [
dict(holiday_date = today, description = 'test') dict(holiday_date = today, description = 'test')
] ]
)) )).insert()
employee = get_employee() 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 = frappe.get_doc(dict(
leave_type_name = 'Test Optional Type', leave_type_name = 'Test Optional Type',
doctype = 'Leave Type', doctype = 'Leave Type',
is_optional_leave = 1, is_optional_leave = 1
holiday_list = holiday_list
)).insert() )).insert()
allocate_leaves(employee, leave_period, leave_type.name, 10) allocate_leaves(employee, leave_period, leave_type.name, 10)
date = get_today() - 1 date = add_days(today, - 1)
leave_application = frappe.get_doc(dict( leave_application = frappe.get_doc(dict(
doctype = 'Leave Application', doctype = 'Leave Application',
employee = employee, employee = employee.name,
leave_type = leave_type.name, leave_type = leave_type.name,
from_date = date, from_date = date,
to_date = date, to_date = date,
)) ))
# can only apply on optional holidays # can only apply on optional holidays
self.assertTrue(NotAnOptionalHoliday, leave_application.insert) self.assertTrue(NotAnOptionalHoliday, leave_application.insert)
leave_application.from_date = today leave_application.from_date = today
leave_application.to_date = today leave_application.to_date = today
leave_application.status = "Approved"
leave_application.insert() leave_application.insert()
leave_application.submit() leave_application.submit()
# check leave balance is reduced # 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): def test_leaves_allowed(self):
# TODO: test cannot allocate more than max leaves # TODO: test cannot allocate more than max leaves
pass pass
@ -285,7 +285,7 @@ class TestLeaveApplication(unittest.TestCase):
def test_max_continuous_leaves(self): def test_max_continuous_leaves(self):
# TODO: test cannot take continuous leaves more than # TODO: test cannot take continuous leaves more than
pass pass
def test_earned_leave(self): def test_earned_leave(self):
leave_period = get_leave_period() leave_period = get_leave_period()
employee = get_employee() employee = get_employee()
@ -297,14 +297,14 @@ class TestLeaveApplication(unittest.TestCase):
earned_leave_frequency = 'Monthly', earned_leave_frequency = 'Monthly',
rounding = 0.5 rounding = 0.5
)).insert() )).insert()
allocate_leaves(employee, leave_period, leave_type.name, 0, eligible_leaves = 12) allocate_leaves(employee, leave_period, leave_type.name, 0, eligible_leaves = 12)
# this method will be called by scheduler # this method will be called by scheduler
allocate_earned_leaves(leave_type.name, leave_period, as_on = half_of_leave_period) 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) self.assertEqual(get_leave_balance(employee, leave_period, leave_type.name), 6)
def make_allocation_record(employee=None, leave_type=None): def make_allocation_record(employee=None, leave_type=None):
frappe.db.sql("delete from `tabLeave Allocation`") frappe.db.sql("delete from `tabLeave Allocation`")
@ -319,4 +319,4 @@ def make_allocation_record(employee=None, leave_type=None):
}) })
allocation.insert(ignore_permissions=True) allocation.insert(ignore_permissions=True)
allocation.submit() allocation.submit()

View File

@ -41,7 +41,6 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -72,7 +71,6 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -102,7 +100,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -134,7 +131,6 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -165,7 +161,37 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 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 "unique": 0
}, },
{ {
@ -196,7 +222,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -227,7 +252,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -259,7 +283,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -291,7 +314,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -323,7 +345,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -355,7 +376,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -386,7 +406,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -416,7 +435,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -447,7 +465,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@ -461,7 +478,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-04-14 13:29:57.066314", "modified": "2018-05-04 18:25:06.719932",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Leave Period", "name": "Leave Period",
@ -470,6 +487,7 @@
"permissions": [ "permissions": [
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@ -489,6 +507,7 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@ -508,6 +527,7 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,

View File

@ -41,7 +41,6 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -73,7 +72,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -104,7 +102,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -136,7 +133,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -166,7 +162,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -198,7 +193,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -228,7 +222,36 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 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 "unique": 0
}, },
{ {
@ -258,7 +281,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -288,7 +310,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -319,7 +340,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -350,7 +370,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -382,7 +401,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -413,7 +431,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -445,7 +462,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -478,102 +494,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 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 "unique": 0
}, },
{ {
@ -604,7 +524,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -635,7 +554,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -668,7 +586,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
@ -701,7 +618,6 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@ -716,7 +632,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-04-14 14:36:46.824289", "modified": "2018-05-03 19:42:23.852331",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "HR", "module": "HR",
"name": "Leave Type", "name": "Leave Type",
@ -724,6 +640,7 @@
"permissions": [ "permissions": [
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@ -743,6 +660,7 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 1, "create": 1,
"delete": 1, "delete": 1,
@ -762,6 +680,7 @@
}, },
{ {
"amend": 0, "amend": 0,
"apply_user_permissions": 0,
"cancel": 0, "cancel": 0,
"create": 0, "create": 0,
"delete": 0, "delete": 0,