diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.json b/erpnext/hr/doctype/leave_allocation/leave_allocation.json index 431adfb16b4..aa203384e86 100644 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.json +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.json @@ -325,7 +325,7 @@ "bold": 1, "collapsible": 0, "columns": 0, - "depends_on": "eval: doc.is_carry_forward != 1", + "depends_on": "eval: doc.carry_forward != 1", "fetch_if_empty": 0, "fieldname": "new_leaves_allocated", "fieldtype": "Float", @@ -351,73 +351,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.is_carry_forward == 1", - "fetch_if_empty": 0, - "fieldname": "old_leaves_allocated", - "fieldtype": "Int", - "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": "Old Leaves Allocated", - "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_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_if_empty": 0, - "fieldname": "is_carry_forward", - "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 carry forward", - "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_in_quick_entry": 0, @@ -437,7 +370,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Add unused leaves from previous allocations", + "label": "Allocate unused leaves from previous allocations", "length": 0, "no_copy": 0, "permlevel": 0, @@ -452,39 +385,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "carry_forward", - "fetch_if_empty": 0, - "fieldname": "carry_forwarded_leaves", - "fieldtype": "Float", - "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": "Unused leaves", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "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_in_quick_entry": 0, @@ -492,6 +392,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "", "fetch_if_empty": 0, "fieldname": "total_leaves_allocated", "fieldtype": "Float", @@ -764,7 +665,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2019-04-04 15:09:33.421008", + "modified": "2019-04-05 15:31:04.627015", "modified_by": "Administrator", "module": "HR", "name": "Leave Allocation", diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index e755da5f543..7ce3143901b 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -18,14 +18,19 @@ class ValueMultiplierError(frappe.ValidationError): pass class LeaveAllocation(Document): def validate(self): self.validate_period() - self.validate_new_leaves_allocated_value() + self.validate_lwp() self.validate_allocation_overlap() self.validate_back_dated_allocation() + if not self.carry_forward: + self.validate_new_leaves_allocated_value() + self.validate_leave_allocation_days() self.set_total_leaves_allocated() self.validate_total_leaves_allocated() - self.validate_lwp() set_employee_name(self) - self.validate_leave_allocation_days() + + def on_update(self): + if self.carry_forward: + self.set_carry_forward_leaves() def validate_leave_allocation_days(self): company = frappe.db.get_value("Employee", self.employee, "company") @@ -44,7 +49,6 @@ class LeaveAllocation(Document): self.validate_new_leaves_allocated_value() self.set_total_leaves_allocated() - frappe.db.set(self,'carry_forwarded_leaves', flt(self.carry_forwarded_leaves)) frappe.db.set(self,'total_leaves_allocated',flt(self.total_leaves_allocated)) self.validate_against_leave_applications() @@ -62,7 +66,7 @@ class LeaveAllocation(Document): 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, carry_forward=0): + def validate_allocation_overlap(self): leave_allocation = frappe.db.sql(""" SELECT name @@ -71,10 +75,10 @@ class LeaveAllocation(Document): employee=%s AND leave_type=%s AND docstatus=1 - AND is_carry_forward={0} + AND carry_forward={0} AND to_date >= %s - AND from_date <= %s""".format(carry_forward), - (self.employee, self.leave_type, self.from_date, self.to_date)) + AND from_date <= %s""" #nosec + .format(self.carry_forward), (self.employee, self.leave_type, self.from_date, self.to_date)) if leave_allocation: frappe.msgprint(_("{0} already allocated for Employee {1} for period {2} to {3}") @@ -94,12 +98,11 @@ class LeaveAllocation(Document): BackDatedAllocationError) def set_total_leaves_allocated(self): - self.carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, - self.leave_type, self.from_date, self.carry_forward) - self.total_leaves_allocated = flt(self.carry_forwarded_leaves) + flt(self.new_leaves_allocated) + self.total_leaves_allocated = flt(self.new_leaves_allocated) - if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave") and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"): + if not self.total_leaves_allocated and not frappe.db.get_value("Leave Type", self.leave_type, "is_earned_leave")\ + and not frappe.db.get_value("Leave Type", self.leave_type, "is_compensatory"): frappe.throw(_("Total leaves allocated is mandatory for Leave Type {0}".format(self.leave_type))) def validate_total_leaves_allocated(self): @@ -119,20 +122,44 @@ class LeaveAllocation(Document): frappe.throw(_("Total allocated leaves {0} cannot be less than already approved leaves {1} for the period").format(self.total_leaves_allocated, leaves_taken), LessAllocationError) def set_carry_forward_leaves(self): - self.validate_allocation_overlap(carry_forward=1) - self.old_leaves_allocated = get_carry_forwarded_leaves(self.employee, self.leave_type, - self.from_date, self.is_carry_forward) + + leaves_allocated + # check number of days to expire, ignore expiry for default value + expiry_days = frappe.db.get_value("Leave Type", + filters={"leave_type": leave_type, "is_carry_forward": 1}, + fieldname="carry_forward_leave_expiry") + + max_leaves_allowed = frappe.db.get_value("Leave Type", self.leave_type, "max_leaves_allowed") + leave_period = get_leave_period(self.from_date, self.to_date, company) + if leave_period: + leave_allocated = get_leave_allocation_for_period(self.employee, self.leave_type, leave_period[0].from_date, leave_period[0].to_date) + + carry_forwarded_leaves = get_carry_forwarded_leaves(self.employee, self.leave_type, + self.from_date, expiry_days) + leaves_allocated += carry_forwarded_leaves + + if leaves_allocated > max_leaves_allowed: + self.total_leaves_allocated = max_leaves_allowed - leaves_allocated + else: + self.total_leaves_allocated = carry_forwarded_leaves def get_leave_allocation_for_period(employee, leave_type, from_date, to_date): leave_allocated = 0 leave_allocations = frappe.db.sql(""" - select employee, leave_type, from_date, to_date, total_leaves_allocated - from `tabLeave Allocation` - where employee=%(employee)s and leave_type=%(leave_type)s - and docstatus=1 - and (from_date between %(from_date)s and %(to_date)s - or to_date between %(from_date)s and %(to_date)s - or (from_date < %(from_date)s and to_date > %(to_date)s)) + SELECT + employee, + leave_type, + from_date, + to_date, + total_leaves_allocated + FROM `tabLeave Allocation` + WHERE + employee=%(employee)s + AND leave_type=%(leave_type)s + AND docstatus=1 + AND (from_date BETWEEN %(from_date)s AND %(to_date)s + OR to_date BETWEEN %(from_date)s AND %(to_date)s + OR (from_date < %(from_date)s AND to_date > %(to_date)s)) """, { "from_date": from_date, "to_date": to_date, @@ -147,31 +174,32 @@ def get_leave_allocation_for_period(employee, leave_type, from_date, to_date): return leave_allocated @frappe.whitelist() -def get_carry_forwarded_leaves(employee, leave_type, date, is_carry_forward=None): +def get_carry_forwarded_leaves(employee, leave_type, date, expiry_days): carry_forwarded_leaves = 0 - if is_carry_forward: - validate_carry_forward(leave_type) + validate_carry_forward(leave_type) + filters = { + "employee": employee, + "leave_type": leave_type, + "docstatus": 1, + "to_date": ("<", date) + } + limit = 1 + if expiry_days: + filters.update(carry_forward=0) + limit = 2 - previous_allocation = frappe.db.sql(""" - SELECT - name, - from_date, - to_date, - total_leaves_allocated - FROM `tabLeave Allocation` - WHERE - employee=%s - AND leave_type=%s - AND docstatus=1 - AND to_date < %s - ORDER BY to_date desc limit 1 - """, (employee, leave_type, date), as_dict=1) - if previous_allocation: - leaves_taken = get_approved_leaves_for_period(employee, leave_type, - previous_allocation[0].from_date, previous_allocation[0].to_date) + previous_allocation = frappe.get_all("Leave Allocation", + filters=filters, + fields=["name","from_date","to_date","total_leaves_allocated"], + order_by="to_date desc", + limit=limit) - carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken) + if previous_allocation: + leaves_taken = get_approved_leaves_for_period(employee, leave_type, + previous_allocation[0].from_date, previous_allocation[0].to_date) + + carry_forwarded_leaves = flt(previous_allocation[0].total_leaves_allocated) - flt(leaves_taken) return carry_forwarded_leaves