def get_payroll_period_days(start_date, end_date, employee, company=None): if not company: company = frappe.db.get_value("Employee", employee, "company") payroll_period = frappe.db.sql( """ select name, start_date, end_date from `tabPayroll Period` where company=%(company)s and %(start_date)s between start_date and end_date and %(end_date)s between start_date and end_date """, { "company": company, "start_date": start_date, "end_date": end_date }, ) if len(payroll_period) > 0: actual_no_of_days = date_diff(getdate(payroll_period[0][2]), getdate(payroll_period[0][1])) + 1 working_days = actual_no_of_days if not cint( frappe.db.get_value("Payroll Settings", None, "include_holidays_in_total_working_days")): holidays = get_holiday_dates_for_employee( employee, getdate(payroll_period[0][1]), getdate(payroll_period[0][2])) working_days -= len(holidays) return payroll_period[0][0], working_days, actual_no_of_days return False, False, False
def update_attendance(self): if self.status != "Approved": return holiday_dates = [] if not frappe.db.get_value("Leave Type", self.leave_type, "include_holiday"): holiday_dates = get_holiday_dates_for_employee(self.employee, self.from_date, self.to_date) for dt in daterange(getdate(self.from_date), getdate(self.to_date)): date = dt.strftime("%Y-%m-%d") attendance_name = frappe.db.exists( "Attendance", dict(employee=self.employee, attendance_date=date, docstatus=("!=", 2)) ) # don't mark attendance for holidays # if leave type does not include holidays within leaves as leaves if date in holiday_dates: if attendance_name: # cancel and delete existing attendance for holidays attendance = frappe.get_doc("Attendance", attendance_name) attendance.flags.ignore_permissions = True if attendance.docstatus == 1: attendance.cancel() frappe.delete_doc("Attendance", attendance_name, force=1) continue self.create_or_update_attendance(attendance_name, date)
def get_holidays_for_employees(employees, from_date, to_date): holidays = {} for employee in employees: holiday_list = get_holiday_list_for_employee(employee) holiday = get_holiday_dates_for_employee(employee, getdate(from_date), getdate(to_date)) if holiday_list not in holidays: holidays[holiday_list] = holiday return holidays
def get_unmarked_days(employee, month, exclude_holidays=0): import calendar month_map = get_month_map() today = get_datetime() joining_date, relieving_date = frappe.get_cached_value( "Employee", employee, ["date_of_joining", "relieving_date"]) start_day = 1 end_day = calendar.monthrange(today.year, month_map[month])[1] + 1 if joining_date and joining_date.month == month_map[month]: start_day = joining_date.day if relieving_date and relieving_date.month == month_map[month]: end_day = relieving_date.day + 1 dates_of_month = [ "{}-{}-{}".format(today.year, month_map[month], r) for r in range(start_day, end_day) ] month_start, month_end = dates_of_month[0], dates_of_month[-1] records = frappe.get_all( "Attendance", fields=["attendance_date", "employee"], filters=[ ["attendance_date", ">=", month_start], ["attendance_date", "<=", month_end], ["employee", "=", employee], ["docstatus", "!=", 2], ], ) marked_days = [get_datetime(record.attendance_date) for record in records] if cint(exclude_holidays): holiday_dates = get_holiday_dates_for_employee(employee, month_start, month_end) holidays = [get_datetime(record) for record in holiday_dates] marked_days.extend(holidays) unmarked_days = [] for date in dates_of_month: date_time = get_datetime(date) if today.day <= date_time.day and today.month <= date_time.month: break if date_time not in marked_days: unmarked_days.append(date) return unmarked_days
def validate_holidays(self): holidays = get_holiday_dates_for_employee(self.employee, self.work_from_date, self.work_end_date) if len(holidays) < date_diff(self.work_end_date, self.work_from_date) + 1: if date_diff(self.work_end_date, self.work_from_date): msg = _("The days between {0} to {1} are not valid holidays." ).format(frappe.bold(format_date(self.work_from_date)), frappe.bold(format_date(self.work_end_date))) else: msg = _("{0} is not a holiday.").format( frappe.bold(format_date(self.work_from_date))) frappe.throw(msg)
def get_max_benefits_remaining(employee, on_date, payroll_period): max_benefits = get_max_benefits(employee, on_date) if max_benefits and max_benefits > 0: have_depends_on_payment_days = False per_day_amount_total = 0 payroll_period_days = get_payroll_period_days(on_date, on_date, employee)[1] payroll_period_obj = frappe.get_doc("Payroll Period", payroll_period) # Get all salary slip flexi amount in the payroll period prev_sal_slip_flexi_total = get_sal_slip_total_benefit_given(employee, payroll_period_obj) if prev_sal_slip_flexi_total > 0: # Check salary structure hold depends_on_payment_days component # If yes then find the amount per day of each component and find the sum sal_struct_name = get_assigned_salary_structure(employee, on_date) if sal_struct_name: sal_struct = frappe.get_doc("Salary Structure", sal_struct_name) for sal_struct_row in sal_struct.get("earnings"): salary_component = frappe.get_doc("Salary Component", sal_struct_row.salary_component) if ( salary_component.depends_on_payment_days == 1 and salary_component.pay_against_benefit_claim != 1 ): have_depends_on_payment_days = True benefit_amount = get_benefit_amount_based_on_pro_rata( sal_struct, salary_component.max_benefit_amount ) amount_per_day = benefit_amount / payroll_period_days per_day_amount_total += amount_per_day # Then the sum multiply with the no of lwp in that period # Include that amount to the prev_sal_slip_flexi_total to get the actual if have_depends_on_payment_days and per_day_amount_total > 0: holidays = get_holiday_dates_for_employee(employee, payroll_period_obj.start_date, on_date) working_days = date_diff(on_date, payroll_period_obj.start_date) + 1 leave_days = calculate_lwp(employee, payroll_period_obj.start_date, holidays, working_days) leave_days_amount = leave_days * per_day_amount_total prev_sal_slip_flexi_total += leave_days_amount return max_benefits - prev_sal_slip_flexi_total return max_benefits