fix: rounding of earned leave is optional (#24782)
diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
index 5e3822e..69d605d 100755
--- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py
@@ -18,7 +18,6 @@
class LeaveAllocation(Document):
def validate(self):
self.validate_period()
- self.validate_new_leaves_allocated_value()
self.validate_allocation_overlap()
self.validate_back_dated_allocation()
self.set_total_leaves_allocated()
@@ -72,11 +71,6 @@
if frappe.db.get_value("Leave Type", self.leave_type, "is_lwp"):
frappe.throw(_("Leave Type {0} cannot be allocated since it is leave without pay").format(self.leave_type))
- def validate_new_leaves_allocated_value(self):
- """validate that leave allocation is in multiples of 0.5"""
- if flt(self.new_leaves_allocated) % 0.5:
- frappe.throw(_("Leaves must be allocated in multiples of 0.5"), ValueMultiplierError)
-
def validate_allocation_overlap(self):
leave_allocation = frappe.db.sql("""
SELECT
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
index a0327bd..3373350 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
@@ -106,12 +106,14 @@
"fieldname": "leaves_allocated",
"fieldtype": "Check",
"hidden": 1,
- "label": "Leaves Allocated"
+ "label": "Leaves Allocated",
+ "no_copy": 1,
+ "print_hide": 1
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-12-31 16:43:30.695206",
+ "modified": "2021-03-01 17:54:01.014509",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Policy Assignment",
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
index a5068bc..4064c56 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py
@@ -6,7 +6,7 @@
import frappe
from frappe.model.document import Document
from frappe import _, bold
-from frappe.utils import getdate, date_diff, comma_and, formatdate
+from frappe.utils import getdate, date_diff, comma_and, formatdate, get_datetime, flt
from math import ceil
import json
from six import string_types
@@ -84,17 +84,52 @@
return allocation.name, new_leaves_allocated
def get_new_leaves(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from frappe.model.meta import get_field_precision
+ precision = get_field_precision(frappe.get_meta("Leave Allocation").get_field("new_leaves_allocated"))
+
+ # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
+ if leave_type_details.get(leave_type).is_compensatory == 1:
+ new_leaves_allocated = 0
+
+ elif leave_type_details.get(leave_type).is_earned_leave == 1:
+ if self.assignment_based_on == "Leave Period":
+ new_leaves_allocated = self.get_leaves_for_passed_months(leave_type, new_leaves_allocated, leave_type_details, date_of_joining)
+ else:
+ new_leaves_allocated = 0
# Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period
- if getdate(date_of_joining) > getdate(self.effective_from):
+ elif getdate(date_of_joining) > getdate(self.effective_from):
remaining_period = ((date_diff(self.effective_to, date_of_joining) + 1) / (date_diff(self.effective_to, self.effective_from) + 1))
new_leaves_allocated = ceil(new_leaves_allocated * remaining_period)
- # Earned Leaves and Compensatory Leaves are allocated by scheduler, initially allocate 0
- if leave_type_details.get(leave_type).is_earned_leave == 1 or leave_type_details.get(leave_type).is_compensatory == 1:
- new_leaves_allocated = 0
+ return flt(new_leaves_allocated, precision)
+
+ def get_leaves_for_passed_months(self, leave_type, new_leaves_allocated, leave_type_details, date_of_joining):
+ from erpnext.hr.utils import get_monthly_earned_leave
+
+ current_month = get_datetime().month
+ current_year = get_datetime().year
+
+ from_date = frappe.db.get_value("Leave Period", self.leave_period, "from_date")
+ if getdate(date_of_joining) > getdate(from_date):
+ from_date = date_of_joining
+
+ from_date_month = get_datetime(from_date).month
+ from_date_year = get_datetime(from_date).year
+
+ months_passed = 0
+ if current_year == from_date_year and current_month > from_date_month:
+ months_passed = current_month - from_date_month
+ elif current_year > from_date_year:
+ months_passed = (12 - from_date_month) + current_month
+
+ if months_passed > 0:
+ monthly_earned_leave = get_monthly_earned_leave(new_leaves_allocated,
+ leave_type_details.get(leave_type).earned_leave_frequency, leave_type_details.get(leave_type).rounding)
+ new_leaves_allocated = monthly_earned_leave * months_passed
return new_leaves_allocated
+
@frappe.whitelist()
def grant_leave_for_multiple_employees(leave_policy_assignments):
leave_policy_assignments = json.loads(leave_policy_assignments)
@@ -156,7 +191,8 @@
def get_leave_type_details():
leave_type_details = frappe._dict()
leave_types = frappe.get_all("Leave Type",
- fields=["name", "is_lwp", "is_earned_leave", "is_compensatory", "is_carry_forward", "expire_carry_forwarded_leaves_after_days"])
+ fields=["name", "is_lwp", "is_earned_leave", "is_compensatory",
+ "is_carry_forward", "expire_carry_forwarded_leaves_after_days", "earned_leave_frequency", "rounding"])
for d in leave_types:
leave_type_details.setdefault(d.name, d)
return leave_type_details
diff --git a/erpnext/hr/doctype/leave_type/leave_type.json b/erpnext/hr/doctype/leave_type/leave_type.json
index a209291..fc577ef 100644
--- a/erpnext/hr/doctype/leave_type/leave_type.json
+++ b/erpnext/hr/doctype/leave_type/leave_type.json
@@ -172,7 +172,7 @@
"fieldname": "rounding",
"fieldtype": "Select",
"label": "Rounding",
- "options": "0.5\n1.0"
+ "options": "\n0.25\n0.5\n1.0"
},
{
"depends_on": "is_carry_forward",
@@ -197,6 +197,7 @@
"label": "Based On Date Of Joining"
},
{
+ "default": "0",
"depends_on": "eval:doc.is_lwp == 0",
"fieldname": "is_ppl",
"fieldtype": "Check",
@@ -213,7 +214,7 @@
"icon": "fa fa-flag",
"idx": 1,
"links": [],
- "modified": "2020-10-15 15:49:47.555105",
+ "modified": "2021-03-02 11:22:33.776320",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Type",
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index e2aa7a4..d57ef59 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -316,13 +316,7 @@
update_previous_leave_allocation(allocation, annual_allocation, e_leave_type)
def update_previous_leave_allocation(allocation, annual_allocation, e_leave_type):
- divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
- if annual_allocation:
- earned_leaves = flt(annual_allocation) / divide_by_frequency[e_leave_type.earned_leave_frequency]
- if e_leave_type.rounding == "0.5":
- earned_leaves = round(earned_leaves * 2) / 2
- else:
- earned_leaves = round(earned_leaves)
+ earned_leaves = get_monthly_earned_leave(annual_allocation, e_leave_type.earned_leave_frequency, e_leave_type.rounding)
allocation = frappe.get_doc('Leave Allocation', allocation.name)
new_allocation = flt(allocation.total_leaves_allocated) + flt(earned_leaves)
@@ -335,6 +329,21 @@
today_date = today()
create_additional_leave_ledger_entry(allocation, earned_leaves, today_date)
+def get_monthly_earned_leave(annual_leaves, frequency, rounding):
+ earned_leaves = 0.0
+ divide_by_frequency = {"Yearly": 1, "Half-Yearly": 6, "Quarterly": 4, "Monthly": 12}
+ if annual_leaves:
+ earned_leaves = flt(annual_leaves) / divide_by_frequency[frequency]
+ if rounding:
+ if rounding == "0.25":
+ earned_leaves = round(earned_leaves * 4) / 4
+ elif rounding == "0.5":
+ earned_leaves = round(earned_leaves * 2) / 2
+ else:
+ earned_leaves = round(earned_leaves)
+
+ return earned_leaves
+
def get_leave_allocations(date, leave_type):
return frappe.db.sql("""select name, employee, from_date, to_date, leave_policy_assignment, leave_policy