def get_data(filters, leave_types): user = frappe.session.user allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date) active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department", "user_id"]) data = [] for employee in active_employees: leave_approvers = get_approvers(employee.department) 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_approved_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) # opening balance opening = get_leave_balance_on(employee.name, leave_type, filters.from_date, allocation_records_based_on_from_date.get(employee.name, frappe._dict())) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get(employee.name, frappe._dict())) row += [opening, leaves_taken, closing] data.append(row) return data
def get_data(filters, leave_types): user = frappe.session.user allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date) active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department", "user_id"]) data = [] for employee in active_employees: leave_approvers = [l.leave_approver for l in frappe.db.sql("""select leave_approver from `tabEmployee Leave Approver` where parent = %s""", (employee.name),as_dict=True)] 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_approved_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) # opening balance opening = get_leave_balance_on(employee.name, leave_type, filters.from_date, allocation_records_based_on_from_date.get(employee.name, frappe._dict())) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get(employee.name, frappe._dict())) row += [opening, leaves_taken, closing] data.append(row) return data
def test_earned_leaves_creation(self): leave_period = get_leave_period() employee = get_employee() leave_type = 'Test Earned Leave Type' if not frappe.db.exists('Leave Type', leave_type): frappe.get_doc(dict( leave_type_name = leave_type, doctype = 'Leave Type', is_earned_leave = 1, earned_leave_frequency = 'Monthly', rounding = 0.5, max_leaves_allowed = 6 )).insert() leave_policy = frappe.get_doc({ "doctype": "Leave Policy", "leave_policy_details": [{"leave_type": leave_type, "annual_allocation": 6}] }).insert() frappe.db.set_value("Employee", employee.name, "leave_policy", leave_policy.name) allocate_leaves(employee, leave_period, leave_type, 0, eligible_leaves = 12) from erpnext.hr.utils import allocate_earned_leaves i = 0 while(i<14): allocate_earned_leaves() i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 6) # validate earned leaves creation without maximum leaves frappe.db.set_value('Leave Type', leave_type, 'max_leaves_allowed', 0) i = 0 while(i<6): allocate_earned_leaves() i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 9)
def test_earned_leaves_creation(self): frappe.db.sql('''delete from `tabLeave Period`''') frappe.db.sql('''delete from `tabLeave Policy Assignment`''') frappe.db.sql('''delete from `tabLeave Allocation`''') frappe.db.sql('''delete from `tabLeave Ledger Entry`''') leave_period = get_leave_period() employee = get_employee() leave_type = 'Test Earned Leave Type' frappe.delete_doc_if_exists("Leave Type", 'Test Earned Leave Type', force=1) frappe.get_doc( dict(leave_type_name=leave_type, doctype='Leave Type', is_earned_leave=1, earned_leave_frequency='Monthly', rounding=0.5, max_leaves_allowed=6)).insert() leave_policy = frappe.get_doc({ "doctype": "Leave Policy", "leave_policy_details": [{ "leave_type": leave_type, "annual_allocation": 6 }] }).insert() data = { "assignment_based_on": "Leave Period", "leave_policy": leave_policy.name, "leave_period": leave_period.name } leave_policy_assignments = create_assignment_for_multiple_employees( [employee.name], frappe._dict(data)) frappe.get_doc( "Leave Policy Assignment", leave_policy_assignments[0]).grant_leave_alloc_for_employee() from erpnext.hr.utils import allocate_earned_leaves i = 0 while (i < 14): allocate_earned_leaves() i += 1 self.assertEqual( get_leave_balance_on(employee.name, leave_type, nowdate()), 6) # validate earned leaves creation without maximum leaves frappe.db.set_value('Leave Type', leave_type, 'max_leaves_allowed', 0) i = 0 while (i < 6): allocate_earned_leaves() i += 1 self.assertEqual( get_leave_balance_on(employee.name, leave_type, nowdate()), 9)
def test_earned_leaves_creation(self): frappe.db.sql("""delete from `tabLeave Period`""") frappe.db.sql("""delete from `tabLeave Policy Assignment`""") frappe.db.sql("""delete from `tabLeave Allocation`""") frappe.db.sql("""delete from `tabLeave Ledger Entry`""") leave_period = get_leave_period() employee = get_employee() leave_type = "Test Earned Leave Type" frappe.delete_doc_if_exists("Leave Type", "Test Earned Leave Type", force=1) frappe.get_doc( dict( leave_type_name=leave_type, doctype="Leave Type", is_earned_leave=1, earned_leave_frequency="Monthly", rounding=0.5, max_leaves_allowed=6, ) ).insert() leave_policy = frappe.get_doc( { "doctype": "Leave Policy", "title": "Test Leave Policy", "leave_policy_details": [{"leave_type": leave_type, "annual_allocation": 6}], } ).insert() data = { "assignment_based_on": "Leave Period", "leave_policy": leave_policy.name, "leave_period": leave_period.name, } leave_policy_assignments = create_assignment_for_multiple_employees( [employee.name], frappe._dict(data) ) from erpnext.hr.utils import allocate_earned_leaves i = 0 while i < 14: allocate_earned_leaves() i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 6) # validate earned leaves creation without maximum leaves frappe.db.set_value("Leave Type", leave_type, "max_leaves_allowed", 0) i = 0 while i < 6: allocate_earned_leaves() i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 9)
def get_data(filters, leave_types): dates = frappe.db.sql( '''select year_start_date, year_end_date from `tabFiscal Year` where name = %s''', filters.fiscal_year) start_date = dates[0][0] end_date = dates[0][1] allocation_records_based_on_to_date_prev_year = get_leave_allocation_records( frappe.utils.add_days(start_date, -1)) allocation_records_based_on_to_date = get_leave_allocation_records( end_date) allocation_records_based_on_from_date = get_leave_allocation_records( start_date) active_employees = frappe.get_all( "Employee", filters={ "status": "Active", "company": filters.company }, fields=["name", "employee_name", "department", "user_id"]) data = [] for employee in active_employees: row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: # leaves taken leaves_taken = get_approved_leaves_for_period( employee.name, leave_type, start_date, end_date) #prev_year_opening prev_year_end_date = frappe.utils.add_days(start_date, -1) prev_year_opening = get_leave_balance_on( employee.name, leave_type, prev_year_end_date, allocation_records_based_on_to_date_prev_year.get( employee.name, frappe._dict())) # opening balance opening = get_total_allocated_leaves(employee.name, leave_type, end_date) added_leave_bal = 0 if (opening - prev_year_opening) > 0: added_leave_bal = opening - prev_year_opening # closing balance closing = get_leave_balance_on( employee.name, leave_type, end_date, allocation_records_based_on_to_date.get( employee.name, frappe._dict())) row += [prev_year_opening, added_leave_bal, leaves_taken, closing] 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_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 test_earned_leave(self): leave_period = get_leave_period() employee = get_employee() leave_type = 'Test Earned Leave Type' if not frappe.db.exists('Leave Type', leave_type): frappe.get_doc(dict( leave_type_name = leave_type, doctype = 'Leave Type', is_earned_leave = 1, earned_leave_frequency = 'Monthly', rounding = 0.5, max_leaves_allowed = 6 )).insert() leave_policy = frappe.get_doc({ "doctype": "Leave Policy", "leave_policy_details": [{"leave_type": leave_type, "annual_allocation": 6}] }).insert() frappe.db.set_value("Employee", employee.name, "leave_policy", leave_policy.name) allocate_leaves(employee, leave_period, leave_type, 0, eligible_leaves = 12) from erpnext.hr.utils import allocate_earned_leaves i = 0 while(i<14): allocate_earned_leaves() i += 1 self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 6)
def validate_balance_leaves(self): if self.from_date and self.to_date: """ overriding starts """ self.total_leave_days = get_number_of_leave_days( self.employee, self.leave_type, self.from_date, self.to_date, self.half_day, self.half_day_date, self.hourly, self.hourly_day_date, self.hours) """ overriding ends """ if self.total_leave_days <= 0: frappe.throw( _("The day(s) on which you are applying for leave are holidays")) if not is_lwp(self.leave_type): self.leave_balance = get_leave_balance_on( self.employee, self.leave_type, self.from_date, docname=self.name, consider_all_leaves_in_the_allocation_period=True) if self.status != "Rejected" and self.leave_balance < self.total_leave_days: if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"): frappe.msgprint( _("Note: There is not enough leave balance for Leave Type {0}" ).format(self.leave_type)) else: frappe.throw( _("There is not enough leave balance for Leave Type {0}"). format(self.leave_type))
def make_leave_application(): allocated_leaves = frappe.get_all("Leave Allocation", fields=['employee', 'leave_type']) for allocated_leave in allocated_leaves: leave_balance = get_leave_balance_on( allocated_leave.employee, allocated_leave.leave_type, frappe.flags.current_date, consider_all_leaves_in_the_allocation_period=True) if leave_balance != 0: if leave_balance == 1: to_date = frappe.flags.current_date else: to_date = add_days(frappe.flags.current_date, random.randint(0, leave_balance - 1)) leave_application = frappe.get_doc({ "doctype": "Leave Application", "employee": allocated_leave.employee, "from_date": frappe.flags.current_date, "to_date": to_date, "leave_type": allocated_leave.leave_type, "status": "Approved" }) try: leave_application.insert() leave_application.submit() frappe.db.commit() except (OverlapError, AttendanceAlreadyMarkedError): frappe.db.rollback()
def validate_balance_leaves(employee, leave_type, from_date, to_date, half_day, half_day_date, status): total_leave_days = 0 if from_date and to_date: total_leave_days = get_number_of_leave_days(employee, leave_type, from_date, to_date, half_day, half_day_date) if total_leave_days == 0: return "The day(s) on which you are applying for leave are holidays. You need not apply for leave." if not is_lwp(leave_type): leave_balance = get_leave_balance_on( employee, leave_type, from_date, consider_all_leaves_in_the_allocation_period=True) if status != "Rejected" and leave_balance < total_leave_days: if frappe.db.get_value("Leave Type", leave_type, "allow_negative"): return "Note: There is not enough leave balance for Leave Type {0}".format( leave_type) else: return "There is not enough leave balance for Leave Type {0}".format( leave_type) return total_leave_days
def get_data(filters, leave_types): allocation_records_based_on_to_date = get_leave_allocation_records( filters.to_date) active_employees = frappe.get_all( "Employee", filters={ "status": "Active", "company": filters.company }, fields=["name", "employee_name", "department"]) data = [] for employee in active_employees: row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: # leaves taken leaves_taken = get_approved_leaves_for_period( employee.name, leave_type, filters.from_date, filters.to_date) # closing balance closing = get_leave_balance_on( employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get( employee.name, frappe._dict())) row += [leaves_taken, closing] data.append(row) return data
def test_leave_grant(self): leave_type = "_Test Leave Type" # create the leave policy leave_policy = frappe.get_doc({ "doctype": "Leave Policy", "leave_policy_details": [{ "leave_type": leave_type, "annual_allocation": 20 }] }).insert() leave_policy.submit() # create employee and assign the leave period employee = "*****@*****.**" employee_doc_name = make_employee(employee) frappe.db.set_value("Employee", employee_doc_name, "leave_policy", leave_policy.name) # clear the already allocated leave frappe.db.sql( '''delete from `tabLeave Allocation` where employee=%s''', "*****@*****.**") # create the leave period leave_period = create_leave_period(add_months(today(), -3), add_months(today(), 3)) # test leave_allocation leave_period.grant_leave_allocation(employee=employee_doc_name) self.assertEqual( get_leave_balance_on(employee_doc_name, leave_type, today()), 20)
def make_leave_application(): allocated_leaves = frappe.get_all("Leave Allocation", fields=['employee', 'leave_type']) for allocated_leave in allocated_leaves: leave_balance = get_leave_balance_on(allocated_leave.employee, allocated_leave.leave_type, frappe.flags.current_date, consider_all_leaves_in_the_allocation_period=True) if leave_balance != 0: if leave_balance == 1: to_date = frappe.flags.current_date else: to_date = add_days(frappe.flags.current_date, random.randint(0, leave_balance-1)) leave_application = frappe.get_doc({ "doctype": "Leave Application", "employee": allocated_leave.employee, "from_date": frappe.flags.current_date, "to_date": to_date, "leave_type": allocated_leave.leave_type, "status": "Approved" }) try: leave_application.insert() leave_application.submit() frappe.db.commit() except (OverlapError): frappe.db.rollback()
def get_record(self, filters): allocation_records_based_on_to_date = get_leave_allocation_records( filters.get('to_date')) data, active_employees = [], frappe.get_all( "Employee", filters={"status": "Active"}, fields=["name", "employee_name", "department"]) for employee in active_employees: row = [ employee.name, employee.employee_name, employee.department, self.get_days_spent(employee.name) ] # if leave type is selected in the filter # leaves taken leaves_taken = get_approved_leaves_for_period( employee.name, filters.get('leave_type'), filters.get('from_date'), filters.get('to_date')) # closing balance closing = get_leave_balance_on( employee.name, filters.get('leave_type'), filters.get('to_date'), allocation_records_based_on_to_date.get( employee.name, frappe._dict())) row += [leaves_taken, closing] data.append(row) print(data)
def test_leave_balance_on_submit(self): ''' check creation of leave allocation on submission of compensatory leave request ''' employee = get_employee() mark_attendance(employee) compensatory_leave_request = get_compensatory_leave_request( employee.name) before = get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, today()) compensatory_leave_request.submit() self.assertEqual( get_leave_balance_on(employee.name, compensatory_leave_request.leave_type, add_days(today(), 1)), before + 1)
def get_data(filters, leave_types): allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department"]) data = [] for employee in active_employees: row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: # leaves taken leaves_taken = get_approved_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get(employee.name, frappe._dict())) row += [leaves_taken, closing] data.append(row) return data
def validate(self): self.posting_date = today() #Update Leave Allocation leave_allocation = get_leave_allocation(self.employee, self.leave_type) if leave_allocation: leave_allocation = frappe.get_doc("Leave Allocation", leave_allocation.name) self.leave_allocation = leave_allocation.name #Total Balance self.total_balance = get_leave_balance_on( self.employee, self.leave_type, self.posting_date, self.posting_date, consider_all_leaves_in_the_allocation_period=True) #TODO Update info leave_allocation self.from_date = leave_allocation.from_date self.to_date = leave_allocation.to_date self.current_cycle = leave_allocation.total_leaves_allocated #Update_leave_ledger_entry update_leave_ledger_entry(leave_allocation.name, self.new_balance, self.total_balance) else: frappe.throw(_("Can not find match Leave Allocation"))
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)) self.leave_balance = get_leave_balance_on( self.employee, self.leave_type, self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True) 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 = self.get_leave_allocation() return True
def fix_balance_leave(doc): if doc.from_date and doc.to_date: doc.total_leave_days = get_number_of_leave_days( doc.employee, doc.leave_type, doc.from_date, doc.to_date, doc.half_day, doc.half_day_date) if doc.total_leave_days <= 0: frappe.throw( _("The day(s) on which you are applying for leave are holidays. You need not apply for leave." )) if not is_lwp(doc.leave_type): doc.leave_balance = get_leave_balance_on( doc.employee, doc.leave_type, doc.from_date, doc.to_date, consider_all_leaves_in_the_allocation_period=True) if doc.status != "Rejected" and ( doc.leave_balance < doc.total_leave_days or not doc.leave_balance): if frappe.db.get_value("Leave Type", doc.leave_type, "allow_negative"): frappe.msgprint( _("Note: There is not enough leave balance for Leave Type {0}" ).format(doc.leave_type)) else: frappe.throw( _("There is not enough leave balance for Leave Type {0}" ).format(doc.leave_type))
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 test_optional_leave(self): leave_period = get_leave_period() today = nowdate() holiday_list = "Test Holiday List for Optional Holiday" employee = get_employee() first_sunday = get_first_sunday(self.holiday_list) optional_leave_date = add_days(first_sunday, 1) if not frappe.db.exists("Holiday List", holiday_list): frappe.get_doc( dict( doctype="Holiday List", holiday_list_name=holiday_list, from_date=add_months(today, -6), to_date=add_months(today, 6), holidays=[ dict(holiday_date=optional_leave_date, description="Test") ], )).insert() frappe.db.set_value("Leave Period", leave_period.name, "optional_holiday_list", holiday_list) leave_type = "Test Optional Type" if not frappe.db.exists("Leave Type", leave_type): frappe.get_doc( dict(leave_type_name=leave_type, doctype="Leave Type", is_optional_leave=1)).insert() allocate_leaves(employee, leave_period, leave_type, 10) date = add_days(first_sunday, 2) leave_application = frappe.get_doc( dict( doctype="Leave Application", employee=employee.name, company="_Test Company", description="_Test Reason", leave_type=leave_type, from_date=date, to_date=date, )) # can only apply on optional holidays self.assertRaises(NotAnOptionalHoliday, leave_application.insert) leave_application.from_date = optional_leave_date leave_application.to_date = optional_leave_date leave_application.status = "Approved" leave_application.insert() leave_application.submit() # check leave balance is reduced self.assertEqual( get_leave_balance_on(employee.name, leave_type, optional_leave_date), 9)
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 test_leave_balance_near_allocaton_expiry(self): employee = get_employee() leave_type = create_leave_type( leave_type_name="_Test_CF_leave_expiry", is_carry_forward=1, expire_carry_forwarded_leaves_after_days=90) leave_type.submit() create_carry_forwarded_allocation(employee, leave_type) self.assertEqual(get_leave_balance_on(employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8)), 21)
def get_leave_balance(employee, date): from erpnext.hr.doctype.leave_application.leave_application import ( get_leave_balance_on, ) carryable_leaves = frappe.get_all("Leave Type", {"is_carry_forward": 1}) return sum( [ get_leave_balance_on(employee, leave_type, date) for leave_type in pluck("name", carryable_leaves) ] )
def test_leave_application_creation_after_expiry(self): # test leave balance for carry forwarded allocation employee = get_employee() leave_type = create_leave_type( leave_type_name="_Test_CF_leave_expiry", is_carry_forward=1, expire_carry_forwarded_leaves_after_days=90) leave_type.submit() create_carry_forwarded_allocation(employee, leave_type) self.assertEquals(get_leave_balance_on(employee.name, leave_type.name, add_days(nowdate(), -85), add_days(nowdate(), -84)), 0)
def test_optional_leave(self): leave_period = get_leave_period() today = nowdate() from datetime import date holiday_list = 'Test Holiday List for Optional Holiday' if not frappe.db.exists('Holiday List', holiday_list): frappe.get_doc(dict( doctype = 'Holiday List', holiday_list_name = holiday_list, from_date = add_months(today, -6), to_date = add_months(today, 6), holidays = [ dict(holiday_date = today, description = 'Test') ] )).insert() employee = get_employee() frappe.db.set_value('Leave Period', leave_period.name, 'optional_holiday_list', holiday_list) leave_type = 'Test Optional Type' if not frappe.db.exists('Leave Type', leave_type): frappe.get_doc(dict( leave_type_name = leave_type, doctype = 'Leave Type', is_optional_leave = 1 )).insert() allocate_leaves(employee, leave_period, leave_type, 10) date = add_days(today, - 1) leave_application = frappe.get_doc(dict( doctype = 'Leave Application', employee = employee.name, company = '_Test Company', description = "_Test Reason", leave_type = leave_type, from_date = date, to_date = date, )) # can only apply on optional holidays self.assertRaises(NotAnOptionalHoliday, leave_application.insert) leave_application.from_date = today leave_application.to_date = today leave_application.status = "Approved" leave_application.insert() leave_application.submit() # check leave balance is reduced self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
def test_optional_leave(self): leave_period = get_leave_period() today = nowdate() from datetime import date holiday_list = 'Test Holiday List for Optional Holiday' if not frappe.db.exists('Holiday List', holiday_list): frappe.get_doc(dict( doctype = 'Holiday List', holiday_list_name = holiday_list, from_date = date(date.today().year, 1, 1), to_date = date(date.today().year, 12, 31), holidays = [ dict(holiday_date = today, description = 'Test') ] )).insert() employee = get_employee() frappe.db.set_value('Leave Period', leave_period.name, 'optional_holiday_list', holiday_list) leave_type = 'Test Optional Type' if not frappe.db.exists('Leave Type', leave_type): frappe.get_doc(dict( leave_type_name = leave_type, doctype = 'Leave Type', is_optional_leave = 1 )).insert() allocate_leaves(employee, leave_period, leave_type, 10) date = add_days(today, - 1) leave_application = frappe.get_doc(dict( doctype = 'Leave Application', employee = employee.name, company = '_Test Company', leave_type = leave_type, from_date = date, to_date = date, )) # can only apply on optional holidays self.assertTrue(NotAnOptionalHoliday, leave_application.insert) leave_application.from_date = today leave_application.to_date = today leave_application.status = "Approved" leave_application.insert() leave_application.submit() # check leave balance is reduced self.assertEqual(get_leave_balance_on(employee.name, leave_type, today), 9)
def update_leave_balance(employees, date): if isinstance(employees, basestring): employees = json.loads(employees) for emp in employees: leave_balance = get_leave_balance_on( employee=emp, date=date, leave_type='Bevorzugter Urlaub', consider_all_leaves_in_the_allocation_period=False) update = frappe.db.sql( """UPDATE `tabEmployee` SET `leave_balance` = '{leave_balance}' WHERE `name` = '{name}'""" .format(name=emp, leave_balance=leave_balance), as_list=True) return True
def get_data(filters, leave_types): allocation_records_based_on_to_date = get_leave_allocation_records( filters.to_date) active_employees = frappe.get_all( "Employee", filters={ "status": "Active", "company": filters.company }, fields=["name", "employee_name", "department"], order_by="employee_name asc") data = [] for employee in active_employees: row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: matched_leave_type = leave_type.lower().replace(' ', '_') if filters.get(matched_leave_type): # leaves taken leaves_taken = get_approved_leaves_for_period( employee.name, leave_type, filters.from_date, filters.to_date) # closing balance closing = get_leave_balance_on( employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get( employee.name, frappe._dict())) # annual leave allocated allocation_records = allocation_records_based_on_to_date.get( employee.name, frappe._dict()) allocation = allocation_records.get(leave_type, frappe._dict()) total_leaves_allocated = flt(allocation.total_leaves_allocated) new_leaves_allocated = flt(allocation.new_leaves_allocated) row += [ new_leaves_allocated, total_leaves_allocated, leaves_taken, closing ] data.append(row) return data
def test_leave_balance_near_allocaton_expiry(self): employee = get_employee() leave_type = create_leave_type( leave_type_name="_Test_CF_leave_expiry", is_carry_forward=1, expire_carry_forwarded_leaves_after_days=90, ) leave_type.insert() create_carry_forwarded_allocation(employee, leave_type) details = get_leave_balance_on( employee.name, leave_type.name, nowdate(), add_days(nowdate(), 8), for_consumption=True ) self.assertEqual(details.leave_balance_for_consumption, 21) self.assertEqual(details.leave_balance, 30)
def get_project_earned_leave_balance(employee, leave_type, start_date=getdate(nowdate())): leave_type_doc = frappe.get_doc("Leave Type", leave_type) if leave_type_doc.is_earned_leave == 0: return None leave_policy = get_employee_leave_policy(employee) if not leave_policy: return None #current balance current_balance = get_leave_balance_on( employee, leave_type, start_date, consider_all_leaves_in_the_allocation_period=True) #end_balance = get_leave_balance_on(employee, leave_type, # start_date, consider_all_leaves_in_the_allocation_period=True) divide_by_frequency = {"Yearly": 1, "Quarterly": 4, "Monthly": 12} days_to_project = date_diff(start_date, get_first_day(getdate(nowdate()))) number_of_months = days_to_project / 30 annual_allocation = frappe.db.sql( """select annual_allocation from `tabLeave Policy Detail` where parent=%s and leave_type=%s""", (leave_policy.name, leave_type_doc.name)) if annual_allocation and annual_allocation[0]: leaves_per_frequency = flt( annual_allocation[0][0]) / divide_by_frequency[ leave_type_doc.earned_leave_frequency] divide_by_frequency = {"Yearly": 12, "Quarterly": 4, "Monthly": 1} future_leaves = (number_of_months / divide_by_frequency[leave_type_doc.earned_leave_frequency] ) * leaves_per_frequency if leave_type_doc.rounding == "0.5": future_leaves = round(future_leaves * 2) / 2 else: future_leaves = round(future_leaves) projected_earned_leave_balance = current_balance + future_leaves return projected_earned_leave_balance
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)) self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.encashment_date or getdate(nowdate()), consider_all_leaves_in_the_allocation_period=True) 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 = self.get_leave_allocation() return True
def update_att_status(attname, deptname, employee, date, employee_name): from erpnext.hr.doctype.leave_application.leave_application import get_number_of_leave_days, get_leave_balance_on doc = frappe.get_doc('Attendance', attname) if doc.status != 'On Leave': #frappe.db.set_value("Attendance", attname, "status", "On Leave") doc.update({'docstatus': 2, 'status': 'On Leave'}) doc.flags.ignore_validate = True doc.flags.ignore_validate_update_after_submit = True doc.save(ignore_permissions=True) dep_doc = frappe.get_doc('Departure', deptname) if dep_doc.status != 'On Leave': dep_doc.update({'docstatus': 2, 'status': 'On Leave'}) dep_doc.flags.ignore_validate = True dep_doc.flags.ignore_validate_update_after_submit = True dep_doc.save(ignore_permissions=True) #add new leave if not frappe.db.get_value('Leave Application', { 'employee': employee, 'from_date': date }) and frappe.db.get_value("Leave Type", _('Annual Leave'), "name"): leave = frappe.new_doc('Leave Application') leave.employee = employee leave.employee_name = employee_name leave.leave_type = _('Annual Leave') leave.from_date = date leave.to_date = date leave.total_leave_days = get_number_of_leave_days( employee, _('Annual Leave'), date, date) leave.status = 'Approved' leave.leave_balance = get_leave_balance_on( employee, _('Annual Leave'), date, consider_all_leaves_in_the_allocation_period=True) leave.description = _('Auto Entry: Discount form Leaves') leave.docstatus = 1 leave.flags.ignore_validate = True leave.insert(ignore_permissions=True) send_email(employee, _('Auto Entry: Discount form Warning'), _('Employee Task Late Warning')) return True
def get_opening_balance(employee: str, leave_type: str, filters: Filters, carry_forwarded_leaves: float) -> float: # allocation boundary condition # opening balance is the closing leave balance 1 day before the filter start date opening_balance_date = add_days(filters.from_date, -1) allocation = get_previous_allocation(filters.from_date, leave_type, employee) if (allocation and allocation.get("to_date") and opening_balance_date and getdate( allocation.get("to_date")) == getdate(opening_balance_date)): # if opening balance date is same as the previous allocation's expiry # then opening balance should only consider carry forwarded leaves opening_balance = carry_forwarded_leaves else: # else directly get leave balance on the previous day opening_balance = get_leave_balance_on(employee, leave_type, opening_balance_date) return opening_balance
def get_data(filters, leave_types): allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date) active_employees = frappe.get_all("Employee", filters = { "status": "Active", "company": filters.company}, fields = ["name", "employee_name", "department"], order_by = "employee_name asc") data = [] for employee in active_employees: row = [employee.name, employee.employee_name, employee.department] for leave_type in leave_types: matched_leave_type = leave_type.lower().replace(' ','_') if filters.get(matched_leave_type): # leaves taken leaves_taken = get_approved_leaves_for_period(employee.name, leave_type, filters.from_date, filters.to_date) # closing balance closing = get_leave_balance_on(employee.name, leave_type, filters.to_date, allocation_records_based_on_to_date.get(employee.name, frappe._dict())) # annual leave allocated allocation_records = allocation_records_based_on_to_date.get(employee.name, frappe._dict()) allocation = allocation_records.get(leave_type, frappe._dict()) total_leaves_allocated = flt(allocation.total_leaves_allocated) new_leaves_allocated = flt(allocation.new_leaves_allocated) row += [new_leaves_allocated, total_leaves_allocated, leaves_taken, closing] data.append(row) return data