def validate(self): if not is_holiday("Holiday List test", self.work_date): odr_list = frappe.db.sql( """select name,work_date from `tabOffice Daily Report` where project = %s order by work_date desc""", (self.project), as_dict=1) if len(odr_list) != 0: prev_date = add_days(self.work_date, -1) if is_holiday("Holiday List test", prev_date): prev_date = add_days(prev_date, -1) frappe.errprint(prev_date) if not frappe.db.exists("Office Daily Report", { 'work_date': prev_date, 'project': self.project }): frappe.throw(_("Previous day Report is still pending")) else: odr = frappe.get_doc("Office Daily Report", odr_list[0].name) if not self.manpower: for od in odr.manpower: self.append("manpower", { "manpower": od.manpower, "prev": od.cum_hours }) if not self.major_equipment: for od in odr.major_equipment: self.append( "major_equipment", { "major_equipment": od.major_equipment, "prev": od.cum_hours }) else: frappe.throw(_("Work Date cannot be a Holiday"))
def send_project_update_email_to_users(project): doc = frappe.get_doc('Project', project) if is_holiday(doc.holiday_list) or not doc.users: return project_update = frappe.get_doc({ "doctype": "Project Update", "project": project, "sent": 0, "date": today(), "time": nowtime(), "naming_series": "UPDATE-.project.-.YY.MM.DD.-", }).insert() subject = "For project %s, update your status" % (project) incoming_email_account = frappe.db.get_value( 'Email Account', dict(enable_incoming=1, default_incoming=1), 'email_id') frappe.sendmail(recipients=get_users_email(doc), message=doc.message, subject=_(subject), reference_doctype=project_update.doctype, reference_name=project_update.name, reply_to=incoming_email_account)
def setup_attendance(): from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday import pandas as pd for employee in frappe.get_all("Employee"): for date in pd.date_range(start="2019-01-01", end=getdate(today())): doc = { "doctype": "Attendance", "employee": employee.name, "attendance_date": date.date(), } if is_holiday(str(date.year), date): doc["status"] = "Absent" elif random.random() < 0.05: doc["status"] = "On Leave" doc["leave_type"] = "Congés payés" if random.random( ) < 0.7 else "RTT" else: doc["status"] = "Present" try: inserted_doc = frappe.get_doc(doc).insert() inserted_doc.submit() except frappe.ValidationError as e: continue
def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None): """Returns a Shift Type for the given employee on the given date. (excluding the holidays) :param employee: Employee for which shift is required. :param for_date: Date on which shift are required :param consider_default_shift: If set to true, default shift is taken when no shift assignment is found. :param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date. """ default_shift = frappe.db.get_value('Employee', employee, 'default_shift') shift_type_name = None shift_assignment_details = frappe.db.get_value('Shift Assignment', {'employee':employee, 'start_date':('<=', for_date), 'docstatus': '1', 'status': "Active"}, ['shift_type', 'end_date']) if shift_assignment_details: shift_type_name = shift_assignment_details[0] # if end_date present means that shift is over after end_date else it is a ongoing shift. if shift_assignment_details[1] and for_date >= shift_assignment_details[1] : shift_type_name = None if not shift_type_name and consider_default_shift: shift_type_name = default_shift if shift_type_name: holiday_list_name = frappe.db.get_value('Shift Type', shift_type_name, 'holiday_list') if not holiday_list_name: holiday_list_name = get_holiday_list_for_employee(employee, False) if holiday_list_name and is_holiday(holiday_list_name, for_date): shift_type_name = None if not shift_type_name and next_shift_direction: MAX_DAYS = 366 if consider_default_shift and default_shift: direction = -1 if next_shift_direction == 'reverse' else +1 for i in range(MAX_DAYS): date = for_date+timedelta(days=direction*(i+1)) shift_details = get_employee_shift(employee, date, consider_default_shift, None) if shift_details: shift_type_name = shift_details.shift_type.name for_date = date break else: direction = '<' if next_shift_direction == 'reverse' else '>' sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc' dates = frappe.db.get_all('Shift Assignment', ['start_date', 'end_date'], {'employee':employee, 'start_date':(direction, for_date), 'docstatus': '1', "status": "Active"}, as_list=True, limit=MAX_DAYS, order_by="start_date "+sort_order) if dates: for date in dates: if date[1] and date[1] < for_date: continue shift_details = get_employee_shift(employee, date[0], consider_default_shift, None) if shift_details: shift_type_name = shift_details.shift_type.name for_date = date[0] break return get_shift_details(shift_type_name, for_date)
def validate_is_holiday(self): holiday_list = get_holiday_list() if is_holiday(holiday_list, self.date): frappe.throw( _("Attendance cannot be marked for {0} as it is a holiday.").format( frappe.bold(formatdate(self.date)) ) )
def is_holiday_date(employee: str, shift_details: Dict) -> bool: holiday_list_name = frappe.db.get_value( "Shift Type", shift_details.shift_type.name, "holiday_list" ) if not holiday_list_name: holiday_list_name = get_holiday_list_for_employee(employee, False) return holiday_list_name and is_holiday(holiday_list_name, shift_details.start_datetime.date())
def execute(filters=None): if not filters: filters = {} if not filters.get("date"): msgprint(_("Please select date"), raise_exception=1) columns = get_columns(filters) date = filters.get("date") holiday_list = get_holiday_list() if is_holiday(holiday_list, filters.get("date")): msgprint( _("No attendance has been marked for {0} as it is a Holiday"). format(frappe.bold(formatdate(filters.get("date"))))) absent_students = get_absent_students(date) leave_applicants = get_leave_applications(date) if absent_students: student_list = [d["student"] for d in absent_students] transportation_details = get_transportation_details(date, student_list) data = [] for student in absent_students: if not student.student in leave_applicants: row = [ student.student, student.student_name, student.student_group ] stud_details = frappe.db.get_value( "Student", student.student, ['student_email_id', 'student_mobile_number'], as_dict=True) if stud_details.student_email_id: row += [stud_details.student_email_id] else: row += [""] if stud_details.student_mobile_number: row += [stud_details.student_mobile_number] else: row += [""] if transportation_details.get(student.student): row += transportation_details.get(student.student) data.append(row) return columns, data
def trigger_emails(): """Send emails to Employees at the given hour asking them what did they work on today""" groups = frappe.get_all("Daily Work Summary Group") for d in groups: group_doc = frappe.get_doc("Daily Work Summary Group", d) if (is_current_hour(group_doc.send_emails_at) and not is_holiday(group_doc.holiday_list) and group_doc.enabled): emails = get_user_emails_from_group(group_doc) # find emails relating to a company if emails: daily_work_summary = frappe.get_doc( dict(doctype="Daily Work Summary", daily_work_summary_group=group_doc.name)).insert() daily_work_summary.send_mails(group_doc, emails)
def mark_absent_for_dates_with_no_attendance(self, employee): """Marks Absents for the given employee on working days in this shift which have no attendance marked. The Absent is marked starting from 'process_attendance_after' or employee creation date. """ start_date, end_date = self.get_start_and_end_dates(employee) # no shift assignment found, no need to process absent attendance records if start_date is None: return holiday_list_name = self.holiday_list if not holiday_list_name: holiday_list_name = get_holiday_list_for_employee(employee, False) start_time = get_time(self.start_time) for date in daterange(getdate(start_date), getdate(end_date)): if is_holiday(holiday_list_name, date): # skip marking absent on a holiday continue timestamp = datetime.combine(date, start_time) shift_details = get_employee_shift(employee, timestamp, True) if shift_details and shift_details.shift_type.name == self.name: attendance = mark_attendance(employee, date, "Absent", self.name) if attendance: frappe.get_doc({ "doctype": "Comment", "comment_type": "Comment", "reference_doctype": "Attendance", "reference_name": attendance, "content": frappe. _("Employee was marked Absent due to missing Employee Checkins." ), }).insert(ignore_permissions=True)
def execute(filters=None): if not filters: filters = {} if not filters.get("date"): msgprint(_("Please select date"), raise_exception=1) holiday_list = get_holiday_list() if is_holiday(holiday_list, filters.get("date")): msgprint( _("No attendance has been marked for {0} as it is a Holiday"). format(frappe.bold(formatdate(filters.get("date"))))) columns = get_columns(filters) active_student_group = get_active_student_group() data = [] for student_group in active_student_group: row = [student_group.name] present_students = 0 absent_students = 0 student_group_strength = get_student_group_strength(student_group.name) student_attendance = get_student_attendance(student_group.name, filters.get("date")) if student_attendance: for attendance in student_attendance: if attendance.status == "Present": present_students = attendance.count elif attendance.status == "Absent": absent_students = attendance.count unmarked_students = student_group_strength - \ (present_students + absent_students) row += [ student_group_strength, present_students, absent_students, unmarked_students ] data.append(row) return columns, data
def update_attendance(self): holiday_list = get_holiday_list() for dt in daterange(getdate(self.from_date), getdate(self.to_date)): date = dt.strftime("%Y-%m-%d") if is_holiday(holiday_list, date): continue attendance = frappe.db.exists("Student Attendance", { "student": self.student, "date": date, "docstatus": ("!=", 2) }) status = "Present" if self.mark_as_present else "Absent" if attendance: # update existing attendance record values = dict() values["status"] = status values["leave_application"] = self.name frappe.db.set_value("Student Attendance", attendance, values) else: # make a new attendance record doc = frappe.new_doc("Student Attendance") doc.student = self.student doc.student_name = self.student_name doc.date = date doc.leave_application = self.name doc.status = status if self.attendance_based_on == "Student Group": doc.student_group = self.student_group else: doc.course_schedule = self.course_schedule doc.insert(ignore_permissions=True, ignore_mandatory=True) doc.submit()
def update_attendance(self): holiday_list = get_holiday_list() for dt in daterange(getdate(self.from_date), getdate(self.to_date)): date = dt.strftime('%Y-%m-%d') if is_holiday(holiday_list, date): continue attendance = frappe.db.exists('Student Attendance', { 'student': self.student, 'date': date, 'docstatus': ('!=', 2) }) status = 'Present' if self.mark_as_present else 'Absent' if attendance: # update existing attendance record values = dict() values['status'] = status values['leave_application'] = self.name frappe.db.set_value('Student Attendance', attendance, values) else: # make a new attendance record doc = frappe.new_doc('Student Attendance') doc.student = self.student doc.student_name = self.student_name doc.date = date doc.leave_application = self.name doc.status = status if self.attendance_based_on == 'Student Group': doc.student_group = self.student_group else: doc.course_schedule = self.course_schedule doc.insert(ignore_permissions=True, ignore_mandatory=True) doc.submit()
def update_if_holiday(self, date): holiday_list = self.holiday_list or get_holiday_list(self.company) while is_holiday(holiday_list, date): date = add_days(date, 1) return date
def get_employee_shift(employee, for_date=None, consider_default_shift=False, next_shift_direction=None): """Returns a Shift Type for the given employee on the given date. (excluding the holidays) :param employee: Employee for which shift is required. :param for_date: Date on which shift are required :param consider_default_shift: If set to true, default shift is taken when no shift assignment is found. :param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date. """ if for_date is None: for_date = nowdate() default_shift = frappe.db.get_value("Employee", employee, "default_shift") shift_type_name = None shift_assignment_details = frappe.db.get_value( "Shift Assignment", { "employee": employee, "start_date": ("<=", for_date), "docstatus": "1", "status": "Active" }, ["shift_type", "end_date"], ) if shift_assignment_details: shift_type_name = shift_assignment_details[0] # if end_date present means that shift is over after end_date else it is a ongoing shift. if shift_assignment_details[ 1] and for_date >= shift_assignment_details[1]: shift_type_name = None if not shift_type_name and consider_default_shift: shift_type_name = default_shift if shift_type_name: holiday_list_name = frappe.db.get_value("Shift Type", shift_type_name, "holiday_list") if not holiday_list_name: holiday_list_name = get_holiday_list_for_employee(employee, False) if holiday_list_name and is_holiday(holiday_list_name, for_date): shift_type_name = None if not shift_type_name and next_shift_direction: MAX_DAYS = 366 if consider_default_shift and default_shift: direction = -1 if next_shift_direction == "reverse" else +1 for i in range(MAX_DAYS): date = for_date + timedelta(days=direction * (i + 1)) shift_details = get_employee_shift(employee, date, consider_default_shift, None) if shift_details: shift_type_name = shift_details.shift_type.name for_date = date break else: direction = "<" if next_shift_direction == "reverse" else ">" sort_order = "desc" if next_shift_direction == "reverse" else "asc" dates = frappe.db.get_all( "Shift Assignment", ["start_date", "end_date"], { "employee": employee, "start_date": (direction, for_date), "docstatus": "1", "status": "Active", }, as_list=True, limit=MAX_DAYS, order_by="start_date " + sort_order, ) if dates: for date in dates: if date[1] and date[1] < for_date: continue shift_details = get_employee_shift(employee, date[0], consider_default_shift, None) if shift_details: shift_type_name = shift_details.shift_type.name for_date = date[0] break return get_shift_details(shift_type_name, for_date)
def update_if_holiday(holiday_list, date): holiday_list = holiday_list or get_holiday_list() while is_holiday(holiday_list, date): date = add_days(date, 1) return date
def update_if_holiday(self, date, holiday_list): while is_holiday(holiday_list, date): date = add_days(date, 1) return date