From 82256bc58b5673a6ffaf9d67f313f91c145553bc Mon Sep 17 00:00:00 2001 From: karthikeyan5 Date: Tue, 11 Jun 2019 14:25:34 +0530 Subject: [PATCH] fix(hr): Auto Attendance > fixing minor bug in shift calculation > adding 'Mark Auto Attendance' button in shift and related fixes > changed employee checkin naming series > added aditional validation for employee checkin > added/updated dashboard for Attendance, Employee, Shift Type --- .../doctype/attendance/attendance_dashboard.py | 13 +++++++++++++ .../hr/doctype/employee/employee_dashboard.py | 4 ++-- .../employee_checkin/employee_checkin.json | 4 ++-- .../doctype/employee_checkin/employee_checkin.py | 2 ++ .../doctype/shift_assignment/shift_assignment.py | 3 ++- erpnext/hr/doctype/shift_type/shift_type.js | 12 +++++++++++- erpnext/hr/doctype/shift_type/shift_type.py | 13 +++++++------ .../doctype/shift_type/shift_type_dashboard.py | 16 ++++++++-------- 8 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 erpnext/hr/doctype/attendance/attendance_dashboard.py diff --git a/erpnext/hr/doctype/attendance/attendance_dashboard.py b/erpnext/hr/doctype/attendance/attendance_dashboard.py new file mode 100644 index 0000000000..5dd9403674 --- /dev/null +++ b/erpnext/hr/doctype/attendance/attendance_dashboard.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'attendance', + 'transactions': [ + { + 'label': '', + 'items': ['Employee Checkin'] + } + ] + } diff --git a/erpnext/hr/doctype/employee/employee_dashboard.py b/erpnext/hr/doctype/employee/employee_dashboard.py index e3cc33d142..162b697ac8 100644 --- a/erpnext/hr/doctype/employee/employee_dashboard.py +++ b/erpnext/hr/doctype/employee/employee_dashboard.py @@ -9,7 +9,7 @@ def get_data(): 'transactions': [ { 'label': _('Leave and Attendance'), - 'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation'] + 'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation', 'Employee Checkin'] }, { 'label': _('Lifecycle'), @@ -40,4 +40,4 @@ def get_data(): 'items': ['Training Event', 'Training Result', 'Training Feedback', 'Employee Skill Map'] }, ] - } \ No newline at end of file + } diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.json b/erpnext/hr/doctype/employee_checkin/employee_checkin.json index d340527538..15ec7c0b1b 100644 --- a/erpnext/hr/doctype/employee_checkin/employee_checkin.json +++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.json @@ -1,6 +1,6 @@ { "allow_import": 1, - "autoname": "ATT-CKIN-.MM.-.YYYY.-.######", + "autoname": "EMP-CKIN-.MM.-.YYYY.-.######", "creation": "2019-06-10 11:56:34.536413", "doctype": "DocType", "engine": "InnoDB", @@ -119,7 +119,7 @@ "label": "Shift Actual End" } ], - "modified": "2019-06-10 11:56:34.536413", + "modified": "2019-06-10 15:33:22.731697", "modified_by": "Administrator", "module": "HR", "name": "Employee Checkin", diff --git a/erpnext/hr/doctype/employee_checkin/employee_checkin.py b/erpnext/hr/doctype/employee_checkin/employee_checkin.py index 997897b554..b0e15d96ed 100644 --- a/erpnext/hr/doctype/employee_checkin/employee_checkin.py +++ b/erpnext/hr/doctype/employee_checkin/employee_checkin.py @@ -28,6 +28,8 @@ class EmployeeCheckin(Document): def fetch_shift(self): shift_actual_timings = get_actual_start_end_datetime_of_shift(self.employee, get_datetime(self.time), True) if shift_actual_timings[0] and shift_actual_timings[1]: + if shift_actual_timings[2].shift_type.determine_check_in_and_check_out == 'Strictly based on Log Type in Employee Checkin' and not self.log_type and not self.skip_auto_attendance: + frappe.throw(_('Log Type is required for check-ins falling in the shift: {0}.').format(shift_actual_timings[2].shift_type.name)) if not self.attendance: self.shift = shift_actual_timings[2].shift_type.name self.shift_actual_start = shift_actual_timings[0] diff --git a/erpnext/hr/doctype/shift_assignment/shift_assignment.py b/erpnext/hr/doctype/shift_assignment/shift_assignment.py index 5b732c4b99..40c78cdf07 100644 --- a/erpnext/hr/doctype/shift_assignment/shift_assignment.py +++ b/erpnext/hr/doctype/shift_assignment/shift_assignment.py @@ -115,11 +115,12 @@ def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=Fals 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', 'date', {'employee':employee, 'date':(direction, for_date), 'docstatus': '1'}, as_list=True, - limit=MAX_DAYS) + limit=MAX_DAYS, order_by="date "+sort_order) for date in dates: shift_details = get_employee_shift(employee, date[0], consider_default_shift, None) if shift_details: diff --git a/erpnext/hr/doctype/shift_type/shift_type.js b/erpnext/hr/doctype/shift_type/shift_type.js index feae889ecd..e633545630 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.js +++ b/erpnext/hr/doctype/shift_type/shift_type.js @@ -3,6 +3,16 @@ frappe.ui.form.on('Shift Type', { refresh: function(frm) { - + frm.add_custom_button( + 'Mark Auto Attendance', + () => frm.call({ + doc: frm.doc, + method: 'process_auto_attendance', + freeze: true, + callback: () => { + frappe.msgprint(__("Attendance has been marked as per employee check-ins")); + } + }) + ); } }); diff --git a/erpnext/hr/doctype/shift_type/shift_type.py b/erpnext/hr/doctype/shift_type/shift_type.py index b77d224cfb..eaf6b1e2d3 100644 --- a/erpnext/hr/doctype/shift_type/shift_type.py +++ b/erpnext/hr/doctype/shift_type/shift_type.py @@ -8,7 +8,7 @@ from datetime import timedelta import frappe from frappe.model.document import Document -from frappe.utils import cint, getdate +from frappe.utils import cint, getdate, get_datetime from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift, get_employee_shift from erpnext.hr.doctype.employee_checkin.employee_checkin import mark_attendance_and_link_log, calculate_working_hours from erpnext.hr.doctype.attendance.attendance import mark_absent @@ -53,9 +53,9 @@ class ShiftType(Document): date_of_joining, relieving_date, employee_creation = frappe.db.get_value("Employee", employee, ["date_of_joining", "relieving_date", "creation"]) if not date_of_joining: date_of_joining = employee_creation.date() - start_date = max(self.process_attendance_after, date_of_joining) - actual_shift_datetime = get_actual_start_end_datetime_of_shift(employee, self.last_sync_of_checkin, True) - last_shift_time = actual_shift_datetime[0] if actual_shift_datetime[0] else self.last_sync_of_checkin + start_date = max(getdate(self.process_attendance_after), date_of_joining) + actual_shift_datetime = get_actual_start_end_datetime_of_shift(employee, get_datetime(self.last_sync_of_checkin), True) + last_shift_time = actual_shift_datetime[0] if actual_shift_datetime[0] else get_datetime(self.last_sync_of_checkin) prev_shift = get_employee_shift(employee, last_shift_time.date()-timedelta(days=1), True, 'reverse') if prev_shift: end_date = min(prev_shift.start_datetime.date(), relieving_date) if relieving_date else prev_shift.start_datetime.date() @@ -64,10 +64,11 @@ class ShiftType(Document): holiday_list_name = self.holiday_list if not holiday_list_name: holiday_list_name = get_holiday_list_for_employee(employee, False) - for date in get_filtered_date_list(employee, start_date, end_date, holiday_list=holiday_list_name): + dates = get_filtered_date_list(employee, start_date, end_date, holiday_list=holiday_list_name) + for date in dates: shift_details = get_employee_shift(employee, date, True) if shift_details and shift_details.shift_type.name == self.name: - mark_absent(employee, date) + mark_absent(employee, date, self.name) def get_assigned_employee(self, from_date=None, consider_default_shift=False): filters = {'date':('>=', from_date), 'shift_type': self.name, 'docstatus': '1'} diff --git a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py index 91dfbad7b1..0a49ddaa9a 100644 --- a/erpnext/hr/doctype/shift_type/shift_type_dashboard.py +++ b/erpnext/hr/doctype/shift_type/shift_type_dashboard.py @@ -2,11 +2,11 @@ from __future__ import unicode_literals from frappe import _ def get_data(): - return { - 'fieldname': 'shift_type', - 'transactions': [ - { - 'items': ['Shift Request', 'Shift Assignment'] - } - ], - } \ No newline at end of file + return { + 'fieldname': 'shift', + 'transactions': [ + { + 'items': ['Attendance', 'Employee Checkin', 'Shift Request', 'Shift Assignment'] + } + ] + }