refactor: Allow multiple attendance records creation for different shifts

This commit is contained in:
Rucha Mahabal 2022-02-21 19:04:09 +05:30
parent f6a12a902f
commit cb3b330097

View File

@ -5,11 +5,15 @@
import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import cint, cstr, formatdate, get_datetime, getdate, nowdate
from frappe.utils import cint, cstr, formatdate, get_datetime, get_link_to_form, getdate, nowdate
from frappe.query_builder import Criterion
from erpnext.hr.utils import get_holiday_dates_for_employee, validate_active_employee
class DuplicateAttendanceError(frappe.ValidationError):
pass
class Attendance(Document):
def validate(self):
from erpnext.controllers.status_updater import validate_status
@ -35,22 +39,12 @@ class Attendance(Document):
frappe.throw(_("Attendance date can not be less than employee's joining date"))
def validate_duplicate_record(self):
res = frappe.db.sql(
"""
select name from `tabAttendance`
where employee = %s
and attendance_date = %s
and name != %s
and docstatus != 2
""",
(self.employee, getdate(self.attendance_date), self.name),
)
if res:
frappe.throw(
_("Attendance for employee {0} is already marked for the date {1}").format(
frappe.bold(self.employee), frappe.bold(self.attendance_date)
)
)
duplicate = get_duplicate_attendance_record(self.employee, self.attendance_date, self.shift, self.name)
if duplicate:
frappe.throw(_("Attendance for employee {0} is already marked for the date {1}: {2}").format(
frappe.bold(self.employee), frappe.bold(self.attendance_date), get_link_to_form("Attendance", duplicate[0].name)),
title=_("Duplicate Attendance"), exc=DuplicateAttendanceError)
def validate_employee_status(self):
if frappe.db.get_value("Employee", self.employee, "status") == "Inactive":
@ -103,6 +97,40 @@ class Attendance(Document):
frappe.throw(_("Employee {0} is not active or does not exist").format(self.employee))
def get_duplicate_attendance_record(employee, attendance_date, shift, name=None):
attendance = frappe.qb.DocType("Attendance")
query = (
frappe.qb.from_(attendance)
.select(attendance.name)
.where(
(attendance.employee == employee)
& (attendance.docstatus < 2)
)
)
if shift:
query = query.where(
Criterion.any([
Criterion.all([
((attendance.shift.isnull()) | (attendance.shift == "")),
(attendance.attendance_date == attendance_date)
]),
Criterion.all([
((attendance.shift.isnotnull()) | (attendance.shift != "")),
(attendance.attendance_date == attendance_date),
(attendance.shift == shift)
])
])
)
else:
query = query.where((attendance.attendance_date == attendance_date))
if name:
query = query.where(attendance.name != name)
return query.run(as_dict=True)
@frappe.whitelist()
def get_events(start, end, filters=None):
events = []
@ -139,26 +167,18 @@ def add_attendance(events, start, end, conditions=None):
if e not in events:
events.append(e)
def mark_attendance(
employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False
):
if not frappe.db.exists(
"Attendance",
{"employee": employee, "attendance_date": attendance_date, "docstatus": ("!=", "2")},
):
company = frappe.db.get_value("Employee", employee, "company")
attendance = frappe.get_doc(
{
"doctype": "Attendance",
"employee": employee,
"attendance_date": attendance_date,
"status": status,
"company": company,
"shift": shift,
"leave_type": leave_type,
}
)
def mark_attendance(employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False):
if not get_duplicate_attendance_record(employee, attendance_date, shift):
company = frappe.db.get_value('Employee', employee, 'company')
attendance = frappe.get_doc({
'doctype': 'Attendance',
'employee': employee,
'attendance_date': attendance_date,
'status': status,
'company': company,
'shift': shift,
'leave_type': leave_type
})
attendance.flags.ignore_validate = ignore_validate
attendance.insert()
attendance.submit()