diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 36a4145467b..2e43721a580 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -515,7 +515,7 @@ def get_remaining_leaves(allocation, leaves_taken, date, expiry): return remaining_leaves - if expiry: + if expiry and allocation.carry_forwarded_leaves: remaining_leaves = _get_remaining_leaves(allocation.carry_forwarded_leaves, expiry) return flt(allocation.new_leaves_allocated) + flt(remaining_leaves) diff --git a/erpnext/hr/doctype/leave_period/leave_period.js b/erpnext/hr/doctype/leave_period/leave_period.js index b8c5f716f5f..bad2b8766c8 100644 --- a/erpnext/hr/doctype/leave_period/leave_period.js +++ b/erpnext/hr/doctype/leave_period/leave_period.js @@ -68,7 +68,7 @@ frappe.ui.form.on('Leave Period', { }, { "label": "Add unused leaves from previous allocations", - "fieldname": "carry_forward_leaves", + "fieldname": "carry_forward", "fieldtype": "Check" } ], diff --git a/erpnext/hr/doctype/leave_period/leave_period.py b/erpnext/hr/doctype/leave_period/leave_period.py index f37efeba0b0..7b0f882035f 100644 --- a/erpnext/hr/doctype/leave_period/leave_period.py +++ b/erpnext/hr/doctype/leave_period/leave_period.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import getdate, cstr, add_days +from frappe.utils import getdate, cstr, add_days, date_diff, getdate, ceil from frappe.model.document import Document from erpnext.hr.utils import validate_overlap, get_employee_leave_policy from erpnext.hr.doctype.leave_allocation.leave_allocation import get_carry_forwarded_leaves @@ -22,8 +22,8 @@ class LeavePeriod(Document): condition_str = " and " + " and ".join(conditions) if len(conditions) else "" - employees = frappe.db.sql_list("select name from tabEmployee where status='Active' {condition}" - .format(condition=condition_str), tuple(values)) + employees = frappe._dict(frappe.db.sql("select name, date_of_joining from tabEmployee where status='Active' {condition}" + .format(condition=condition_str), tuple(values))) return employees @@ -37,29 +37,29 @@ class LeavePeriod(Document): def grant_leave_allocation(self, grade=None, department=None, designation=None, - employee=None, carry_forward_leaves=0): - employees = self.get_employees({ + employee=None, carry_forward=0): + employee_records = self.get_employees({ "grade": grade, "department": department, "designation": designation, "name": employee }) - if employees: - if len(employees) > 20: + if employee_records: + if len(employee_records) > 20: frappe.enqueue(grant_leave_alloc_for_employees, timeout=600, - employees=employees, leave_period=self, carry_forward_leaves=carry_forward_leaves) + employee_records=employee_records, leave_period=self, carry_forward=carry_forward) else: - grant_leave_alloc_for_employees(employees, self, carry_forward_leaves) + grant_leave_alloc_for_employees(employee_records, self, carry_forward) else: frappe.msgprint(_("No Employee Found")) -def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leaves=0): +def grant_leave_alloc_for_employees(employee_records, leave_period, carry_forward=0): leave_allocations = [] - existing_allocations_for = get_existing_allocations(employees, leave_period.name) + existing_allocations_for = get_existing_allocations(list(employee_records.keys()), leave_period.name) leave_type_details = get_leave_type_details() count = 0 - for employee in employees: + for employee in employee_records.keys(): if employee in existing_allocations_for: continue count +=1 @@ -68,10 +68,10 @@ def grant_leave_alloc_for_employees(employees, leave_period, carry_forward_leave for leave_policy_detail in leave_policy.leave_policy_details: if not leave_type_details.get(leave_policy_detail.leave_type).is_lwp: leave_allocation = create_leave_allocation(employee, leave_policy_detail.leave_type, - leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward_leaves) + leave_policy_detail.annual_allocation, leave_type_details, leave_period, carry_forward, employee_records.get(employee)) leave_allocations.append(leave_allocation) frappe.db.commit() - frappe.publish_progress(count*100/len(set(employees) - set(existing_allocations_for)), title = _("Allocating leaves...")) + frappe.publish_progress(count*100/len(set(employee_records.keys()) - set(existing_allocations_for)), title = _("Allocating leaves...")) if leave_allocations: frappe.msgprint(_("Leaves has been granted sucessfully")) @@ -100,21 +100,30 @@ def get_leave_type_details(): leave_type_details.setdefault(d.name, d) return leave_type_details -def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward_leaves): - allocation = frappe.new_doc("Leave Allocation") - allocation.employee = employee - allocation.leave_type = leave_type - allocation.from_date = leave_period.from_date - allocation.to_date = leave_period.to_date +def create_leave_allocation(employee, leave_type, new_leaves_allocated, leave_type_details, leave_period, carry_forward, date_of_joining): + ''' Creates leave allocation for the given employee in the provided leave period ''' + if carry_forward and not leave_type_details.get(leave_type).is_carry_forward: + carry_forward = 0 + + # Calculate leaves at pro-rata basis for employees joining after the beginning of the given leave period + if getdate(date_of_joining) > getdate(leave_period.from_date): + remaining_period = ((date_diff(leave_period.to_date, date_of_joining) + 1) / (date_diff(leave_period.to_date, leave_period.from_date) + 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 - allocation.new_leaves_allocated = new_leaves_allocated - allocation.leave_period = leave_period.name - if carry_forward_leaves: - if leave_type_details.get(leave_type).is_carry_forward: - allocation.carry_forward = carry_forward_leaves + allocation = frappe.get_doc(dict( + doctype="Leave Allocation", + employee=employee, + leave_type=leave_type, + from_date=leave_period.from_date, + to_date=leave_period.to_date, + new_leaves_allocated=new_leaves_allocated, + leave_period=leave_period.name, + carry_forward=carry_forward + )) allocation.save(ignore_permissions = True) allocation.submit() return allocation.name \ No newline at end of file