fix: only expire carry forwarded allocation via scheduler
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 72c538f..28dd4e8 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -264,7 +264,7 @@
"erpnext.projects.doctype.project.project.update_project_sales_billing",
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
"erpnext.quality_management.doctype.quality_review.quality_review.review",
- "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.check_expired_allocation"
+ "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation"
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status"
],
"daily_long": [
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 1c8fed3..e85d5ce 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -6,14 +6,34 @@
import frappe
from frappe.model.document import Document
from frappe import _
-from frappe.utils import add_days, today
+from frappe.utils import add_days, today, flt
class LeaveLedgerEntry(Document):
def validate_entries(self):
- leave_records = frappe.get_all('Leave Ledger Entry', ['leaves'])
- if sum(record.get("leaves") for record in leave_records) <0:
+ total_leaves = frappe.get_all('Leave Ledger Entry', ['SUM(leaves)'])
+ if total_leaves < 0:
frappe.throw(_("Invalid Ledger Entry"))
+ def on_cancel(self):
+ # allow cancellation of expiry leaves
+ if not self.is_expired:
+ frappe.throw(_("Only expired allocation can be cancelled"))
+
+def validate_leave_allocation_against_leave_application(ledger):
+ ''' Checks that leave allocation has no leave application against it '''
+ leave_application_records = frappe.get_all("Leave Ledger Entry",
+ filters={
+ 'employee': ledger.employee,
+ 'leave_type': ledger.leave_type,
+ 'transaction_type': 'Leave Application',
+ 'from_date': (">=", ledger.from_date),
+ 'to_date': ('<=', ledger.to_date)
+ }, fields=['transaction_name'])
+
+ if leave_application_records:
+ frappe.throw(_("Leave allocation %s is linked with leave application %s"
+ % (ledger.transaction_name, ', '.join(leave_application_records))))
+
def create_leave_ledger_entry(ref_doc, args, submit=True):
ledger = frappe._dict(
doctype='Leave Ledger Entry',
@@ -22,6 +42,8 @@
leave_type=ref_doc.leave_type,
transaction_type=ref_doc.doctype,
transaction_name=ref_doc.name,
+ is_carry_forward=0,
+ is_expired=0
)
ledger.update(args)
if submit:
@@ -32,67 +54,58 @@
def delete_ledger_entry(ledger):
''' Delete ledger entry on cancel of leave application/allocation/encashment '''
- leave_application_records = []
- # prevent deletion when leave application has been created after allocation
if ledger.transaction_type == "Leave Allocation":
- leave_application_records = frappe.get_all("Leave Ledger Entry",
+ validate_leave_allocation_against_leave_application(ledger)
+
+ frappe.db.sql("""DELETE
+ FROM `tabLeave Ledger Entry`
+ WHERE
+ `transaction_name`=%s""", (ledger.transaction_name))
+
+def process_expired_allocation():
+ ''' Check if a carry forwarded allocation has expired and create a expiry ledger entry '''
+
+ # fetch leave type records that has carry forwarded leaves expiry
+ leave_type_records = frappe.db.get_values("Leave Type", filters={
+ 'carry_forward_leave_expiry': (">", 0)
+ }, fieldname=['name'])
+
+ if leave_type_records:
+ leave_type = [record[0] for record in leave_type_records]
+ expired_allocation = frappe.get_all("Leave Ledger Entry",
filters={
- 'employee': ledger.employee,
- 'leave_type': ledger.leave_type,
- 'transaction_type': 'Leave Application',
- 'from_date': (">=", ledger.from_date),
- 'to_date': ('<=', ledger.to_date)
- },
- fields=['transaction_name'])
-
- if not leave_application_records:
- frappe.db.sql("""DELETE
- FROM `tabLeave Ledger Entry`
- WHERE
- `transaction_name`=%s""", (ledger.transaction_name))
- else:
- frappe.throw(_("Leave allocation %s is linked with leave application %s"
- % (ledger_entry, ', '.join(leave_application_records))))
-
-def check_expired_allocation():
- ''' Checks for expired allocation by comparing to_date with current_date and
- based on that creates an expiry ledger entry '''
- expired_allocation = frappe.get_all("Leave Ledger Allocation",
- filters={
- 'to_date': today(),
- 'transaction_type': 'Leave Allocation'
- },
- fields=['*'])
+ 'to_date': today(),
+ 'transaction_type': 'Leave Allocation',
+ 'is_carry_forward': 1,
+ 'leave_type': ('in', leave_type)
+ }, fields=['leaves', 'to_date', 'employee', 'leave_type'])
if expired_allocation:
create_expiry_ledger_entry(expired_allocation)
def create_expiry_ledger_entry(expired_allocation):
+ ''' Create expiry ledger entry for carry forwarded leaves '''
for allocation in expired_allocation:
- filters = {
- 'employee': allocation.employee,
- 'leave_type': allocation.leave_type,
- 'from_date': ('>=', allocation.from_date),
- }
- # get only application ledger entries in case of carry forward
- if allocation.is_carry_forward:
- filters.update(dict(transaction_type='Leave Application'))
- leave_records = frappe.get_all("Leave Ledger Entry",
- filters=filters,
- fields=['leaves'])
-
- leaves = sum(record.get("leaves") for record in leave_records)
-
- if allocation.is_carry_forward:
- leaves = allocation.leaves + leaves
+ leaves_taken = get_leaves_taken(allocation)
+ leaves = flt(allocation.leaves) + flt(leaves_taken)
if leaves > 0:
args = frappe._dict(
leaves=allocation.leaves * -1,
- to_date='',
- is_carry_forward=allocation.is_carry_forward,
+ to_date=allocation.to_date,
+ is_carry_forward=1,
is_expired=1,
from_date=allocation.to_date
)
- create_leave_ledger_entry(allocation, args)
\ No newline at end of file
+ create_leave_ledger_entry(allocation, args)
+
+def get_leaves_taken(allocation):
+ return frappe.db.get_value("Leave Ledger Entry",
+ filters={
+ 'employee': allocation.employee,
+ 'leave_type': allocation.leave_type,
+ 'from_date': ('>=', allocation.from_date),
+ 'to_date': ('<=', allocation.to_date),
+ 'transaction_type': 'Leave application'
+ }, fieldname=['SUM(leaves)'])
\ No newline at end of file