def get_employee_shift_working_hours(emp_id): working_hours = [] if emp_id: working_hours = frappe.db.sql(""" SELECT FLOOR(emp.working_hours / total) AS working_hours FROM (SELECT COUNT(0) AS total, SUM(TIME_FORMAT(TIMEDIFF(st.shift_end_time, st.shift_start_time), '%h')) AS working_hours FROM `tabAttendance` AS st WHERE st.attendance_date >= DATE_FORMAT(NOW(), '%Y-01-01') AND employee = '{0}' GROUP BY employee) AS emp """.format(emp_id), as_dict=True) if len(working_hours) == 0: default_time = dict({ "start_time": get_config_by_name("default_shift_start_time", "09:00:00"), "end_time": get_config_by_name("default_shift_end_time", "18:00:00"), "date": datetime.datetime.today().strftime('%Y-%m-%d') }) working_hours = calculate_working_hours_for_default(default_time) else: working_hours = working_hours[0]['working_hours'] return working_hours
def prepare_employee_data(self): _df_start_time = get_config_by_name("default_shift_start_time", "09:00:00") _df_end_time = get_config_by_name("default_shift_end_time", "18:00:00") _employee_cond = "" if self.employee: _employee_cond = """ AND e.name = "{0}" """.format(self.employee) self.employee_attendance = frappe.db.sql(""" SELECT e.name, IF(st.start_time IS NULL,%(start_time)s,st.start_time) as start_time, IF(st.end_time IS NULL,%(end_time)s,st.end_time) as end_time, e.company, mc.week_day_date as week_day, e.department, IF(h.name IS NULL AND ch.name IS NULL AND erch.name IS NULL, IF(week_day_date = e.date_of_joining, "{1}", "{2}"), IF(ch.name IS NOT NULL, "{3}", "{4}") ) as attendance_status, IF(h.name IS NULL AND ch.name IS NULL AND erch.name IS NULL, "Absent", "Present") as status FROM `month_calendar` mc INNER JOIN `tabEmployee` e ON mc.emp_fk = "employee" AND e.status = "Active" {0} LEFT JOIN `tabAttendance` att ON att.employee = e.name AND att.attendance_date = mc.week_day_date LEFT JOIN `tabEmployee` es ON es.name = e.name INNER JOIN `tabShift Type` st ON st.name = es.shift_type LEFT JOIN `tabHoliday List` hl ON hl.name = e.holiday_list LEFT JOIN `tabHoliday` h ON h.parent = hl.name AND h.holiday_date = mc.week_day_date LEFT JOIN `tabCompany` c ON c.name = e.company LEFT JOIN `tabHoliday List` chl ON chl.name = c.default_holiday_list LEFT JOIN `tabHoliday` ch ON ch.parent = chl.name AND ch.holiday_date = mc.week_day_date LEFT JOIN `tabHoliday List` erhl ON erhl.name = st.holiday_list LEFT JOIN `tabHoliday` erch ON erch.parent = erhl.name AND erch.holiday_date = mc.week_day_date WHERE att.name IS NULL AND mc.week_day_date >= e.date_of_joining GROUP BY e.name, mc.week_day_date """.format(_employee_cond, ROSTER_STATUS_FLEXIBLE, ROSTER_STATUS_ON, ROSTER_STATUS_HOLIDAY, ROSTER_STATUS_OFF), { "start_time": _df_start_time, "end_time": _df_end_time }, as_dict=True)
def get_reversal_button(emp_id, processed_id, attendance_date): if (check_advance_privilege_by_name( get_config_by_name('CAN_REVERSE_ATTENDANCE_PENALTY')) == False or EmployeeRoster.is_cutoff_passed( attendance_date, get_config_by_name('PENALTY_REVERSAL_MONTHS_LIMIT', 2)) == True): return "Processed" else: return """<button type="button" class="btn-primary btn btn-sm process-style" onclick="reverse_penalty('{0}','{1}')">{2}</button>""".format( emp_id, processed_id, "Reverse")
def before_save_attendance(doc, event): if doc.attendance_status == ROSTER_STATUS_HOLIDAY and doc.flags.ignore_permissions == False: frappe.throw(_("You cannot manually update roster status to holiday")) calculate_late_arrivals(doc) doc.shift_start_time = doc.shift_start_time if doc.shift_start_time != None else get_config_by_name("default_shift_start_time", "09:00:00") doc.shift_end_time = doc.shift_end_time if doc.shift_end_time != None else get_config_by_name("default_shift_end_time", "18:00:00") user_id = frappe.session.user auth_role = frappe.get_roles(user_id) emp_attendance = [] if doc.amended_from is not None: emp_attendance = frappe.db.get_value("Attendance", {"name": doc.amended_from}, "*") if ADMINISTRATOR != user_id: # if(emp_attendance): # emp_attendance.attendance_date = emp_attendance.attendance_date.strftime('%Y-%m-%d') # # Only employee with advanced privilege can update privious date attendance for roster # today_date = datetime.strftime(datetime.today(), '%Y-%m-%d') # if emp_attendance.attendance_date < today_date and check_advance_privilege_by_name(get_config_by_name('CAN_UPDATE_PREVIOUS_DAY_ROSTER')) == False: # frappe.throw(_("You cannot update previous date roster")) # Validate not to update attendance except AttendanceManager if ATTENDANCE_MANAGER not in auth_role and doc.flags.ignore_permissions == False: if emp_attendance: # validate for attendance_date if doc.attendance_date is not None: if str(doc.attendance_date) != str(emp_attendance.attendance_date): frappe.throw(_("You cannot update attendance date")) # validate for check_in if doc.check_in is not None: if str(doc.check_in) != str(emp_attendance.check_in): frappe.throw(_("You cannot update attendance check in time")) # validate for check_out if doc.check_out is not None: if str(doc.check_out) != str(emp_attendance.check_out): frappe.throw(_("You cannot update attendance check out time")) # validate for employee_id if doc.employee is not None: if doc.employee != emp_attendance.employee: frappe.throw(_("You cannot update employee code")) # Restrict self update for Attendance if doc.employee is not None: if doc.employee == get_employee_code(): frappe.throw(_("You cannot update your attendance"))
def validate_dates(doctype, event_name): ''' validate cutoff dates ''' try: date_obj = datetime.datetime.now() la_date = str_to_date(date_obj.strftime("%Y-%m-%d"), '%Y-%m-%d') processding_date = str_to_date( date_obj.strftime("%Y-%m-") + str(get_config_by_name('MONTH_PROCESSING_DATE', '20')), '%Y-%m-%d') restrict_leave_date = str_to_date( date_obj.strftime("%Y-%m-") + str(get_config_by_name('RESTRICTED_LEAVES_DATE', '22')), '%Y-%m-%d') from_date = str_to_date(doctype.from_date, '%Y-%m-%d') to_date = str_to_date(doctype.to_date, '%Y-%m-%d') except Exception as err: print(err) ErrorHandler.log_error(str(err)) ''' if there is creation date then we consider creation date as leave application date la_date ''' if hasattr(doctype, 'creation'): la_date = str_to_date(get_datetime(doctype.creation), '%Y-%m-%d') new_la = False if hasattr(doctype, '__islocal'): new_la = True ''' Check advance privilege and validate dates of cutoff''' if (check_advance_privilege_by_name( get_config_by_name('ADVANCE_PRIV_APPLY_LEAVE_AFTER_CUTOFF_DATE')) == False and new_la == True): if (la_date >= restrict_leave_date and (from_date <= processding_date or to_date <= processding_date)): frappe.throw( _("You cannot apply for a previous day leave after the cutoff date" )) elif ( (from_date <= processding_date - dateutil.relativedelta.relativedelta(months=1) or to_date <= processding_date - dateutil.relativedelta.relativedelta(months=1))): frappe.throw( _("You cannot apply for a previous day leave after the cutoff date" )) #TODO: Make validation configurable ''' Check advance privilege Validation for casual leave '''
def attendance_api(attendance=[]): if attendance: body = attendance else: body = get_post_body() AttendanceCalculation.MIN_EARLY = get_config_by_name("MIN_EARLY", 0) AttendanceCalculation.MAX_LATE = get_config_by_name("MAX_LATE", 0) AttendanceCalculation.GRACE_MINS = get_config_by_name("GRACE_MINS", 0) AttendanceCalculation.EMPLOYEE_PREFIX = getenv("EMPLOYEE_PREFIX", "EMPG") response = list() if body: for att_data in body: if "user_id" in att_data: attendance = AttendanceCalculation(att_data["user_id"]) response.append(attendance.add_update_attendance(att_data)) return response
def get(): args = get_form_params() try: args["filters"] = args["filters"] + frappe.get_doc( { "doctype": "Doctype List Rules", "doc": args["doctype"] }).get_filters() except Exception as err: frappe.log_error(err) # OVERRIDE START HERE # Show only custom reports which are defined in array role = get_user_role() report_list = get_config_by_name( 'COMMON_REPORT_ALLOWED') + get_config_by_name('REPORTS_ALLOWED_LIST') if args['doctype'] == 'Report': if role is not ADMINISTRATOR: args['filters'].append(['Report', 'disabled', '=', 0]) args['page_length'] = 500 results = execute(**args) exec_arr = [] if args['doctype'] == 'Report': if role is not ADMINISTRATOR: for result in results: if result.name in report_list: exec_arr.append(result) elif 'total_count' in result: exec_arr.append(result) else: exec_arr = results else: exec_arr = results # OVERRIDE END HERE data = compress(exec_arr, args=args) return data
def employee_leave_allocation(doctype, employee_detail): ''' Restrict leave allocation call for HR User, HR Manager and administrator''' if employee_detail and any(x in frappe.get_roles( ) for x in [LINE_MANAGER, HR_USER, HR_MANAGER, ADMINISTRATOR]) == True: if (doctype.employment_type == EMPLOYMENT_TYPE_PERMANENT): allot_leaves(doctype) elif (doctype.employment_type == get_config_by_name( 'EMPLOYMENT_TYPE_PROBATION', "Probationary")): allot_leaves(doctype, True) if doctype.holiday_list: update_holiday_status(doctype.holiday_list, [doctype.name]) ''' Update leave approver if line manager changed for employee''' if employee_detail[2] is not None or doctype.reports_to: if doctype.reports_to and doctype.reports_to != employee_detail[2]: update_leave_approver(doctype.name, doctype.reports_to)
def get_leave_status_list(islocal,employee=None): # Check User with Special Privillige or not if(check_advance_privilege_by_name(get_config_by_name('ADVANCE_PRIV_AUTO_APPROVE_LEAVE'))): return [LEAVE_STATUS_OPEN, LEAVE_STATUS_APPROVED, LEAVE_STATUS_REJECTED, LEAVE_STATUS_CANCELLED] if(any(x in frappe.get_roles() for x in [HR_MANAGER, HR_USER, LINE_MANAGER,ADMINISTRATOR]) and islocal != "new" ): if (employee is not None and employee == get_employee_code()): return [LEAVE_STATUS_OPEN, LEAVE_STATUS_CANCELLED] return [LEAVE_STATUS_OPEN, LEAVE_STATUS_APPROVED, LEAVE_STATUS_REJECTED, LEAVE_STATUS_CANCELLED] if(islocal=="new"): return [LEAVE_STATUS_OPEN] else: return [LEAVE_STATUS_OPEN, LEAVE_STATUS_CANCELLED]
def validate_leave_approver(doctype): reports_to = None if(check_advance_privilege_by_name(get_config_by_name('ADVANCE_PRIV_AUTO_APPROVE_LEAVE')) == False): # reports_to = '' reports_to_code = frappe.get_value("Employee", doctype.employee, "reports_to") if(reports_to_code): reports_to = frappe.get_value("Employee", reports_to_code, "user_id") dept_leave_approver = frappe.db.get_value('Department Approver', {'parent': doctype.department,'parentfield': 'leave_approvers','approver':doctype.leave_approver}, 'approver') hr_role = None if HR_MANAGER in frappe.get_roles(frappe.session.user) or HR_USER in frappe.get_roles(frappe.session.user): hr_role = True ''' Also validating HR User and HR Manager can approve leaves''' if(doctype.status in [LEAVE_STATUS_APPROVED, LEAVE_STATUS_REJECTED] and doctype.employee == get_employee_code()): frappe.throw(_("You cannot approve/reject your own leaves")) elif (doctype.status in [LEAVE_STATUS_APPROVED, LEAVE_STATUS_REJECTED] and doctype.employee not in get_auth_team_ids(True) and hr_role is None): frappe.throw(_("You cannot approve/reject this leaves"))
def allocate_probationary_leaves(): employees = frappe.get_all("Employee", filters={ 'status': 'Active', 'employment_type': get_config_by_name( 'EMPLOYMENT_TYPE_PROBATION', "Probationary") }) for employee in employees: try: doc = frappe.get_doc("Employee", employee.name) allot_leaves(doc, True) print("employee:", employee.name) frappe.db.commit() except Exception as err: frappe.log_error(err) pass
def sync(): ''' Fucntion to sync other departments roster with empghr roster ''' _max_iterations = 10000 _errors = [] _success = [] _iteration = 0 response = dict() global _BODY global _VALID_EMPLOYEES _BODY = get_post_body() ''' Get allowed user to sync attendance ''' users = get_config_by_name("ATTENDANCE_SYNC_USERS", []) if frappe.session.user in users: if _BODY: validation_err, _errors = validate_required_fields() if validation_err == False and len(_errors) < 1: _chunk = divide_chunks(_BODY, 20) while True or _iteration <= _max_iterations: try: _data = next(_chunk) for att in _data: ''' Add or update attendance''' status, result_obj = add_or_update_attendance( _VALID_EMPLOYEES[att.get("email")], att) if status == False and result_obj: att["error"] = result_obj _errors.append(att) else: _success.append(result_obj) _iteration += 1 frappe.db.commit() except StopIteration: break response = {"code": 200, "success": _success} else: response = {"code": 201, "error": _errors} return response else: return { "code": 403, "error": [_("You are not allowed to sync roster/attendance.")] }
def get_leave_approver(employee, department=None): leave_approver = "" employee_detail = frappe.db.get_value( 'Employee', employee, ['department', 'reports_to', 'user_id']) if employee_detail and employee_detail[1]: leave_approver = frappe.db.get_value('Employee', employee_detail[1], 'user_id') if not leave_approver and employee_detail and employee_detail[0]: leave_approver = frappe.db.get_value( 'Department Approver', { 'parent': employee_detail[0], 'parentfield': 'leave_approvers', 'idx': 1 }, 'approver') if leave_approver is None and check_advance_privilege_by_name( get_config_by_name('ADVANCE_PRIV_AUTO_APPROVE_LEAVE')): if employee_detail and employee_detail[ 2] and frappe.session.user != ADMINISTRATOR: leave_approver = employee_detail[2] return leave_approver
def get_config_by_name(self, *args): return get_config_by_name(args[0])
def validate_required_fields(): _params = [ "object_id", "shift_start_time", "shift_end_time", "attendance_status", "email", "attendance_date" ] _required_err = False _errors = [] _invalid_employees = [] _idx = -1 _all_roster_statuses = dict() global _BODY global _VALID_EMPLOYEES _roster_mapping = get_config_by_name("ROSTER_MAPPINGS", {}) _roster_statuses = _roster_mapping.get(frappe.session.user) if _roster_statuses is not None and _roster_statuses: for att in _BODY: _idx += 1 _err = False for key in _params: if key not in att: _required_err = True _err = True att["error"] = "{} is required.".format(key) _errors.append(att) break if _err == False: _err = True if att.get("email") not in _VALID_EMPLOYEES: ''' If user is not in valid employees then get employee code by email and update valid_employees and invalid_employees''' if att.get("email") in _invalid_employees: ''' If not employee associated with email then break current itration of loop with error''' continue employee_obj = frappe.db.get_value( 'Employee', {'user_id': att.get("email")}, [ 'name', 'employee_name', 'department', 'sub_department' ], as_dict=True) if employee_obj: _VALID_EMPLOYEES[att.get("email")] = employee_obj else: _invalid_employees.append(att.get("email")) att["error"] = "No Employee associated with {0}.".format( att.get("email")) _errors.append(att) continue ''' Validate shift start,end time and attendance date''' if att.get("shift_start_time"): try: time.strptime(att.get("shift_start_time"), '%Y-%m-%d %H:%M:%S') except ValueError: att["error"] = "Invalid shift start time {0}.".format( att.get("shift_start_time")) _errors.append(att) continue if att.get("shift_end_time"): try: time.strptime(att.get("shift_end_time"), '%Y-%m-%d %H:%M:%S') except ValueError: att["error"] = "Invalid shift end time {0}.".format( att.get("shift_end_time")) _errors.append(att) continue ''' Validate shift start,end time''' if att.get("shift_start_time") and att.get("shift_end_time"): try: if time.strptime(att.get("shift_end_time"), '%Y-%m-%d %H:%M:%S') < time.strptime( att.get("shift_start_time"), '%Y-%m-%d %H:%M:%S'): att["error"] = "Shift end time must be greater than shift start time." _errors.append(att) continue except ValueError: att["error"] = "Invalid shift start or end time {0}, {1}.".format( att.get("shift_start_time"), att.get("shift_end_time")) _errors.append(att) continue if att.get("attendance_date"): try: att["attendance_date"] = datetime.strptime( att.get("attendance_date"), '%Y-%m-%d').date() except ValueError: att["error"] = "Invalid attendance date {0}.".format( att.get("attendance_date")) _errors.append(att) continue ''' Check attendance date is before or after cutoff date''' if EmployeeRoster.is_cutoff_passed( att.get("attendance_date")) == True: att["error"] = "Cannot update roster on date {0} before cutoff Date.".format( att.get("attendance_date")) _errors.append(att) continue ''' Check maping of roster status with attendance status''' _status = _roster_statuses.get( str(att.get("attendance_status"))) if _status and _status not in _all_roster_statuses: status = frappe.db.get_value("Roster Status", {"name": _status}, "parent_status") if status is not None and status: _all_roster_statuses[_status] = status else: att["error"] = "Roster status {0} is not linked with any Attendance Status.".format( att.get("attendance_status")) _errors.append(att) continue elif not _status: att["error"] = "Roster status {0} is not linked with any Attendance Status.".format( att.get("attendance_status")) _errors.append(att) continue _BODY[_idx]["attendance_status"] = _status _BODY[_idx]["status"] = _all_roster_statuses[_status] _err = False if _err == True: _required_err = True else: _errors.append(_("Roster Statuses mapping not found.")) return _required_err, _errors
def assign_employee_shift(employee, shift_type): if shift_type == None: return _today = datetime.today() today_date = _today.strftime("%Y-%m-%d") month = _today.strftime("%m") year = _today.strftime("%Y") attendace_processed = frappe.db.get_value("Attendance Penalties Processed", filters={ "employee": employee, "month": month, "year": year }) if attendace_processed != None: today_date = """{0}-{1}-{2}""".format(year, month, MONTHLY_ATTENDANCE_DATE) emp_future_leaves = frappe.db.sql( """select * from `tabLeave Application` where employee = %s and (from_date >= %s OR to_date >= %s) and docstatus = 1""", (employee, today_date, today_date)) if len(emp_future_leaves) > 0: frappe.throw( _("You cannot add/change shift because employee have applied for future leave" )) _df_start_time = get_config_by_name("default_shift_start_time", "09:00:00") _df_end_time = get_config_by_name("default_shift_end_time", "18:00:00") try: emp_attendance_list = frappe.db.sql(""" SELECT att.name, att.attendance_date, IF(st.start_time IS NULL,%(start_time)s,st.start_time) as start_time, IF(st.end_time IS NULL,%(end_time)s,st.end_time) as end_time, IF(h.name IS NULL AND ch.name IS NULL AND erch.name IS NULL, "On", "Off") as attendance_status, IF(h.name IS NULL AND ch.name IS NULL AND erch.name IS NULL, "Absent", "Present") as status FROM `tabAttendance` att LEFT JOIN `tabEmployee` emp ON att.employee = emp.name LEFT JOIN `tabShift Type` st ON st.name = %(shift_name)s LEFT JOIN `tabHoliday List` hl ON hl.name = emp.holiday_list LEFT JOIN `tabHoliday` h ON h.parent = hl.name AND h.holiday_date = att.attendance_date LEFT JOIN `tabCompany` c ON c.name = emp.company LEFT JOIN `tabHoliday List` chl ON chl.name = c.default_holiday_list LEFT JOIN `tabHoliday` ch ON ch.parent = chl.name AND ch.holiday_date = att.attendance_date LEFT JOIN `tabHoliday List` erhl ON erhl.name = st.holiday_list LEFT JOIN `tabHoliday` erch ON erch.parent = erhl.name AND erch.holiday_date = att.attendance_date WHERE att.attendance_date > %(today_date)s AND att.docstatus = 1 AND att.employee = %(employee)s """, { "shift_name": shift_type, "start_time": _df_start_time, "end_time": _df_end_time, "employee": employee, "today_date": today_date }, as_dict=True) except Exception as err: ErrorHandler.log_error(str(err)) frappe.throw(_("did not find roster against new employee shift")) if len(emp_attendance_list) > 0: _att_list = [emp_sh["name"] for emp_sh in emp_attendance_list] unlock_doc_list("Attendance", _att_list) for attendance in emp_attendance_list: try: emp_att = frappe.get_doc("Attendance", attendance["name"]) emp_att.shift_start_time = attendance["start_time"] emp_att.shift_end_time = attendance["end_time"] emp_att.status = attendance["status"] emp_att.attendance_status = attendance["attendance_status"] emp_att.docstatus = 1 emp_att.save() except Exception as err: ErrorHandler.log_error(str(err)) frappe.throw(_("There is an error while updating Attendance"))
def update_leave_quota(self, year, month, employee_ids): errors = list() if len(employee_ids) == 0: return False _df_start_time = get_config_by_name("default_shift_start_time", "09:00:00") _df_end_time = get_config_by_name("default_shift_end_time", "18:00:00") _sql = """ SELECT `eap`.*, SUM(eap.penalty) AS `calculated_val`, app.name as processed_id, `apr`.*, `emp`.`department`, `emp`.`employee_name`, `emp`.`date_of_joining`, HOUR(TIMEDIFF( if(shift.end_time IS NOT NULL,shift.end_time, "{3}"), if(shift.start_time IS NOT NULL,shift.start_time, "{4}") )) as working_hours FROM `tabEmployee Attendance Penalties` AS `eap` INNER JOIN `tabAttendance Policy Rules` AS `apr` ON eap.attendance_policy_rules = apr.name INNER JOIN `tabEmployee` AS `emp` ON eap.employee = emp.employee LEFT JOIN `tabShift Type` as shift ON shift.name = emp.shift_type LEFT JOIN `tabAttendance Penalties Processed` app on app.employee = emp.employee AND app.month = eap.month AND app.year = eap.year WHERE (eap.year = '{0}' AND eap.month = '{1}' AND eap.employee IN ({2})) GROUP BY `eap`.`employee` """.format(year, month, "'" + "','".join(employee_ids) + "'", _df_end_time, _df_start_time) employee_list = frappe.db.sql(_sql, as_dict=True) date_start = datetime.today() from_date = posting_date = str_to_date(date_start, "%Y-%m-%d") month_start_date = str_to_date(datetime(int(year), int(month), 01),'%Y-%m-%d') for emp in employee_list: penalty_min = emp["calculated_val"] penalty_days = round((penalty_min/60) / int(emp["working_hours"]) , 2) response = self.create_earned_leave_quota(emp["employee"]) if(response): errors.append("{0} ---> {1}.".format(response,emp["employee"])) continue if emp["policy_multiplier"] > 0: _itr = 20 date_of_joining = str_to_date(emp["date_of_joining"],'%Y-%m-%d') if(date_of_joining > month_start_date): month_start_date = date_of_joining while penalty_days > 0 and _itr > 0: leaves = self.get_prioritized_pending_leaves(emp["employee"], month_start_date) if bool(leaves): _quota = 0 if leaves["remaining_leaves"] <= 0 : break elif leaves["remaining_leaves"] > penalty_days: _quota = penalty_days penalty_days = 0 else: # if remaining leaves < penalty days _quota = leaves["remaining_leaves"] penalty_days = penalty_days - leaves["remaining_leaves"] to_date = datetime.strftime(month_start_date + timedelta(days=math.ceil(_quota) -1), "%Y-%m-%d") try : leave_application = frappe.get_doc({"doctype" : "Leave Application"}) set_name_by_naming_series(leave_application) leave_approver = get_report_to(emp["employee"],True) _sql = """ INSERT INTO `tabLeave Application` (name, employee, employee_name, from_date, to_date, status, total_leave_days, docstatus, leave_type, description, department, leave_balance, follow_via_email, leave_approver, posting_date, creation, modified) VALUES ("{}", "{}", "{}", "{}", "{}", "Approved", "{}", 1, "{}", "Penalty Deduction", "{}", "{}", 0, "{}", "{}", NOW(), NOW() ) """.format(leave_application.name, emp["employee"], emp["employee_name"], month_start_date, to_date, _quota, leaves["leave_type"], emp["department"], leaves["leave_balance"],leave_approver ,posting_date) frappe.db.sql(_sql) except Exception as err: frappe.log_error(err) errors.append("{0} ---> {1}.".format(_("Unable to update quota"),emp["employee"])) break try : frappe.get_doc({ "doctype" : "Employee Penalty Leaves", "leave_application" : leave_application.name, "attendance_penalties_processed" : emp["processed_id"] }).submit() except Exception as err: frappe.log_error(err) errors.append("{0} ---> {1}.".format(_("Unable to log quota updation"),emp["employee"])) break else: errors.append("{0} ---> {1}.".format(_("didn't find any leave to deduct quota"),emp["employee"])) break _itr -= 1 else: reward_minutes = emp["unit_value_to"] - emp["value"] reward_days = round(float(reward_minutes/60) / int(emp["working_hours"]) , 2) start_date, end_date = get_monthly_diff_dates() earned_leaves = get_leave_allocation_detail(emp["employee"], "Earned Leave", start_date, end_date) if len(earned_leaves) > 0: try : leave_allocation = frappe.get_doc("Leave Allocation", earned_leaves[0]["name"]) leave_allocation_log = frappe.get_doc({ "doctype" : "Leave Allocation Log", }) leave_allocation_log.total_leaves_allocated = leave_allocation.total_leaves_allocated leave_allocation_log.employee = leave_allocation.employee leave_allocation_log.leave_type = leave_allocation.leave_type leave_allocation_log.to_date = leave_allocation.to_date leave_allocation_log.from_date = leave_allocation.from_date leave_allocation_log.insert() leave_allocation.update({"new_leaves_allocated": float(reward_days) + float(earned_leaves[0]["total_leaves_allocated"])}) leave_allocation.flags.ignore_permissions = True leave_allocation.save() except Exception as err: errors.append("{0} ---> {1}.".format(_("Unable to update quota"),emp["employee"])) return errors
def allot_leaves(doctype, probationary=False): date_obj = datetime.datetime.now() total_days_in_year = 365 joining_date = str_to_date(doctype.date_of_joining, "%Y-%m-%d") j_year = joining_date.year curr_year = conf_year = date_obj.year system_launching_year = get_config_by_name('SYSTEM_LAUNCH_YEAR', 2019) if (j_year < system_launching_year): j_year = system_launching_year if probationary: confirmation_date = str_to_date(doctype.final_confirmation_date, "%Y-%m-%d") conf_year = confirmation_date.year while conf_year >= j_year: leave_period_start = year_start = str_to_date( date_obj.strftime(str(j_year) + "-01-01"), "%Y-%m-%d") year_end = str_to_date(date_obj.strftime(str(j_year) + "-12-31"), "%Y-%m-%d") if (joining_date > year_start): leave_days = flt(total_days_in_year - get_date_diff_in_days(year_start, joining_date)) leave_period_start = joining_date else: leave_days = total_days_in_year if probationary and conf_year == j_year: if conf_year == joining_date.year: leave_days = flt( get_date_diff_in_days(joining_date, confirmation_date)) else: leave_days = flt( get_date_diff_in_days(year_start, confirmation_date)) leaves = get_auto_assigned_leaves_detail(probationary) for leave in leaves: if (leave and leave.max_leaves_allowed > 0): alloted_leave_balance = round( flt(leave_days * leave.max_leaves_allowed) / total_days_in_year, 2) Leave_allocation_obj = frappe.get_doc( {"doctype": "Leave Allocation"}) Leave_allocation_obj.employee = doctype.employee Leave_allocation_obj.leave_type = leave.name Leave_allocation_obj.from_date = leave_period_start Leave_allocation_obj.to_date = year_end Leave_allocation_obj.new_leaves_allocated = alloted_leave_balance alloted_leave_by_type = get_leave_allocation_record( doctype.employee, leave.name, leave_period_start, year_end) if (alloted_leave_balance > 0): if (not alloted_leave_by_type): Leave_allocation_obj.docstatus = 1 Leave_allocation_obj.flags.ignore_permissions = True try: Leave_allocation_obj.insert() except Exception as err: frappe.throw(_(err)) ErrorHandler.log_error(str(err)) elif (alloted_leave_by_type and leave.prorated_on_probation): if alloted_leave_by_type[ 0].total_leaves_allocated != alloted_leave_balance: la_doc = frappe.get_doc( "Leave Allocation", alloted_leave_by_type[0].name) la_doc.update({ "new_leaves_allocated": alloted_leave_balance }) la_doc.flags.ignore_permissions = True la_doc.save() j_year = j_year + 1