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 import frappe
from frappe import _ from frappe import _
from frappe.model.document import Document 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 from erpnext.hr.utils import get_holiday_dates_for_employee, validate_active_employee
class DuplicateAttendanceError(frappe.ValidationError):
pass
class Attendance(Document): class Attendance(Document):
def validate(self): def validate(self):
from erpnext.controllers.status_updater import validate_status 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")) frappe.throw(_("Attendance date can not be less than employee's joining date"))
def validate_duplicate_record(self): def validate_duplicate_record(self):
res = frappe.db.sql( duplicate = get_duplicate_attendance_record(self.employee, self.attendance_date, self.shift, self.name)
"""
select name from `tabAttendance` if duplicate:
where employee = %s frappe.throw(_("Attendance for employee {0} is already marked for the date {1}: {2}").format(
and attendance_date = %s frappe.bold(self.employee), frappe.bold(self.attendance_date), get_link_to_form("Attendance", duplicate[0].name)),
and name != %s title=_("Duplicate Attendance"), exc=DuplicateAttendanceError)
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)
)
)
def validate_employee_status(self): def validate_employee_status(self):
if frappe.db.get_value("Employee", self.employee, "status") == "Inactive": 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)) 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() @frappe.whitelist()
def get_events(start, end, filters=None): def get_events(start, end, filters=None):
events = [] events = []
@ -139,26 +167,18 @@ def add_attendance(events, start, end, conditions=None):
if e not in events: if e not in events:
events.append(e) events.append(e)
def mark_attendance(employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False):
def mark_attendance( if not get_duplicate_attendance_record(employee, attendance_date, shift):
employee, attendance_date, status, shift=None, leave_type=None, ignore_validate=False company = frappe.db.get_value('Employee', employee, 'company')
): attendance = frappe.get_doc({
if not frappe.db.exists( 'doctype': 'Attendance',
"Attendance", 'employee': employee,
{"employee": employee, "attendance_date": attendance_date, "docstatus": ("!=", "2")}, 'attendance_date': attendance_date,
): 'status': status,
company = frappe.db.get_value("Employee", employee, "company") 'company': company,
attendance = frappe.get_doc( 'shift': shift,
{ 'leave_type': leave_type
"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.flags.ignore_validate = ignore_validate
attendance.insert() attendance.insert()
attendance.submit() attendance.submit()