def calculate_leaves_details(filters, leave_type, employee): ledger_entries = get_leave_ledger_entries(filters.from_date, filters.to_date, employee.name, leave_type) #Leaves Deducted consist of both expired and leaves taken leaves_deducted = get_leaves_for_period( employee.name, leave_type, filters.from_date, filters.to_date) * -1 # removing expired leaves leaves_taken = leaves_deducted - remove_expired_leave(ledger_entries) opening = get_leave_balance_on(employee.name, leave_type, filters.from_date) new_allocation, expired_allocation = get_allocated_and_expired_leaves( ledger_entries, filters.from_date, filters.to_date) #removing leaves taken from expired_allocation expired_leaves = max(expired_allocation - leaves_taken, 0) #Formula for calculating closing balance closing = max(opening + new_allocation - (leaves_taken + expired_leaves), 0) return [opening, new_allocation, expired_leaves, leaves_taken, closing]
def get_allocated_and_expired_leaves( from_date: str, to_date: str, employee: str, leave_type: str ) -> Tuple[float, float, float]: new_allocation = 0 expired_leaves = 0 carry_forwarded_leaves = 0 records = get_leave_ledger_entries(from_date, to_date, employee, leave_type) for record in records: # new allocation records with `is_expired=1` are created when leave expires # these new records should not be considered, else it leads to negative leave balance if record.is_expired: continue if record.to_date < getdate(to_date): # leave allocations ending before to_date, reduce leaves taken within that period # since they are already used, they won't expire expired_leaves += record.leaves expired_leaves += get_leaves_for_period(employee, leave_type, record.from_date, record.to_date) if record.from_date >= getdate(from_date): if record.is_carry_forward: carry_forwarded_leaves += record.leaves else: new_allocation += record.leaves return new_allocation, expired_leaves, carry_forwarded_leaves
def expire_carried_forward_allocation(allocation): """Expires remaining leaves in the on carried forward allocation""" from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period leaves_taken = get_leaves_for_period( allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date, skip_expired_leaves=False, ) leaves = flt(allocation.leaves) + flt(leaves_taken) # allow expired leaves entry to be created if leaves > 0: args = frappe._dict( transaction_name=allocation.name, transaction_type="Leave Allocation", leaves=allocation.leaves * -1, is_carry_forward=allocation.is_carry_forward, is_expired=1, from_date=allocation.to_date, to_date=allocation.to_date, ) create_leave_ledger_entry(allocation, args)
def get_data(filters): leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC") conditions = get_conditions(filters) user = frappe.session.user department_approver_map = get_department_leave_approver_map(filters.get('department')) active_employees = frappe.get_list('Employee', filters=conditions, fields=['name', 'employee_name', 'department', 'user_id', 'leave_approver']) data = [] for leave_type in leave_types: if len(active_employees) > 1: data.append({ 'leave_type': leave_type }) else: row = frappe._dict({ 'leave_type': leave_type }) for employee in active_employees: leave_approvers = department_approver_map.get(employee.department_name, []).append(employee.leave_approver) if (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \ or ("HR Manager" in frappe.get_roles(user)): if len(active_employees) > 1: row = frappe._dict() row.employee = employee.name, row.employee_name = employee.employee_name leaves_taken = get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1 new_allocation, expired_leaves = get_allocated_and_expired_leaves(filters.from_date, filters.to_date, employee.name, leave_type) opening = get_leave_balance_on(employee.name, leave_type, add_days(filters.from_date, -1)) #allocation boundary condition row.leaves_allocated = new_allocation row.leaves_expired = expired_leaves - leaves_taken if expired_leaves - leaves_taken > 0 else 0 row.opening_balance = opening row.leaves_taken = leaves_taken # not be shown on the basis of days left it create in user mind for carry_forward leave row.closing_balance = (new_allocation + opening - (row.leaves_expired + leaves_taken)) row.indent = 1 data.append(row) new_leaves_allocated = 0 return data
def get_data(filters: Filters) -> List: leave_types = frappe.db.get_list("Leave Type", pluck="name", order_by="name") conditions = get_conditions(filters) user = frappe.session.user department_approver_map = get_department_leave_approver_map(filters.get("department")) active_employees = frappe.get_list( "Employee", filters=conditions, fields=["name", "employee_name", "department", "user_id", "leave_approver"], ) data = [] for leave_type in leave_types: if len(active_employees) > 1: data.append({"leave_type": leave_type}) else: row = frappe._dict({"leave_type": leave_type}) for employee in active_employees: leave_approvers = department_approver_map.get(employee.department_name, []).append( employee.leave_approver ) if ( (leave_approvers and len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) or ("HR Manager" in frappe.get_roles(user)) ): if len(active_employees) > 1: row = frappe._dict() row.employee = employee.name row.employee_name = employee.employee_name leaves_taken = ( get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1 ) new_allocation, expired_leaves, carry_forwarded_leaves = get_allocated_and_expired_leaves( filters.from_date, filters.to_date, employee.name, leave_type ) opening = get_opening_balance(employee.name, leave_type, filters, carry_forwarded_leaves) row.leaves_allocated = new_allocation row.leaves_expired = expired_leaves row.opening_balance = opening row.leaves_taken = leaves_taken # not be shown on the basis of days left it create in user mind for carry_forward leave row.closing_balance = new_allocation + opening - (row.leaves_expired + leaves_taken) row.indent = 1 data.append(row) return data
def get_data(filters, leave_types): user = frappe.session.user conditions = get_conditions(filters) if filters.to_date <= filters.from_date: frappe.throw(_("From date can not be greater than than To date")) if filters.to_date <= filters.from_date: frappe.throw(_("From date can not be greater than than To date")) active_employees = frappe.get_all("Employee", filters=conditions, fields=[ "name", "employee_name", "department", "user_id", "leave_approver" ]) department_approver_map = get_department_leave_approver_map( filters.get('department')) data = [] for employee in active_employees: leave_approvers = department_approver_map.get(employee.department_name, []) if employee.leave_approver: leave_approvers.append(employee.leave_approver) if (len(leave_approvers) and user in leave_approvers) or (user in [ "Administrator", employee.user_id ]) or ("HR Manager" in frappe.get_roles(user)): row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: # leaves taken leaves_taken = get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1 # opening balance opening = get_leave_balance_on(employee.name, leave_type, filters.from_date) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date) row += [opening, leaves_taken, closing] data.append(row) return data
def get_leave_details(employee, date): '''Override white listed function get_leave_details for calculate leaves details Because after adding hourly leave funcionality leave balanace, leave used and pending leaves qouta calculted in decimals and this add almost 10+ digits after decimal''' allocation_records = get_leave_allocation_records(date, employee).get( employee, frappe._dict()) leave_allocation = {} for d in allocation_records: allocation = allocation_records.get(d, frappe._dict()) date = allocation.to_date leaves_taken = round( get_leaves_for_period(employee, d, allocation.from_date, date, status="Approved"), 2) leaves_pending = round( get_leaves_for_period(employee, d, allocation.from_date, date, status="Open"), 2) remaining_leaves = round( allocation.total_leaves_allocated - leaves_taken - leaves_pending, 2) leave_allocation[d] = { "total_leaves": allocation.total_leaves_allocated, "leaves_taken": leaves_taken, "pending_leaves": leaves_pending, "remaining_leaves": remaining_leaves } ret = { 'leave_allocation': leave_allocation, 'leave_approver': get_leave_approver(employee) } return ret
def get_data(filters): leave_types = frappe.db.sql_list( "SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC") conditions = get_conditions(filters) user = frappe.session.user department_approver_map = get_department_leave_approver_map( filters.get('department')) active_employees = frappe.get_list('Employee', filters=conditions, fields=[ 'name', 'employee_name', 'department', 'user_id', 'leave_approver' ]) data = [] for leave_type in leave_types: data.append({'leave_type': leave_type}) for employee in active_employees: leave_approvers = department_approver_map.get( employee.department_name, []).append(employee.leave_approver) if (len(leave_approvers) and user in leave_approvers) or (user in ["Administrator", employee.user_id]) \ or ("HR Manager" in frappe.get_roles(user)): row = frappe._dict({ 'employee': employee.name, 'employee_name': employee.employee_name }) leaves_taken = get_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) * -1 opening = get_leave_balance_on(employee.name, leave_type, filters.from_date) closing = get_leave_balance_on(employee.name, leave_type, filters.to_date) row.opening_balance = opening row.leaves_taken = leaves_taken row.closing_balance = closing row.indent = 1 data.append(row) return data
def get_leave_details_for_encashment(self): salary_structure = get_assigned_salary_structure( self.employee, self.encashment_date or getdate(nowdate())) if not salary_structure: frappe.throw( _("No Salary Structure assigned for Employee {0} on given date {1}" ).format(self.employee, self.encashment_date)) if not frappe.db.get_value("Leave Type", self.leave_type, "allow_encashment"): frappe.throw( _("Leave Type {0} is not encashable").format(self.leave_type)) allocation = self.get_leave_allocation() if not allocation: frappe.throw( _("No Leaves Allocated to Employee: {0} for Leave Type: {1}"). format(self.employee, self.leave_type)) self.leave_balance = ( allocation.total_leaves_allocated - allocation.carry_forwarded_leaves_count # adding this because the function returns a -ve number + get_leaves_for_period(self.employee, self.leave_type, allocation.from_date, self.encashment_date)) encashable_days = self.leave_balance - frappe.db.get_value( "Leave Type", self.leave_type, "encashment_threshold_days") self.encashable_days = encashable_days if encashable_days > 0 else 0 per_day_encashment = frappe.db.get_value( "Salary Structure", salary_structure, "leave_encashment_amount_per_day") self.encashment_amount = (self.encashable_days * per_day_encashment if per_day_encashment > 0 else 0) self.leave_allocation = allocation.name return True