Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 171
CRAP
0.00% covered (danger)
0.00%
0 / 4606
AttendanceService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 171
723350.00
0.00% covered (danger)
0.00%
0 / 4606
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 3
 __clone
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 getInstance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 7
 getDLApprovedStudents
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 23
 applyDLToAttendance
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 setStudentDLToAttendance
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 19
 searchAttndceBlkdStudentRequest
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 49
 getAttendanceHours
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 blockAttendance
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 5
 blockStudentAttendance
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 29
 isStudentBlockedByDate
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 4
 updateBlockedAttendance
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 4
 unBlockStudentAttendance
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 27
 updateUnblockedAttendance
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 4
 getAttendanceCount
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 23
 getAttendanceRule
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 checkAttendanceLimitValid
0.00% covered (danger)
0.00%
0 / 1
240.00
0.00% covered (danger)
0.00%
0 / 68
 getAttendanceConfirmedStaffDetails
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 20
 updateStudentsAttendance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 updateStudentsTempAttendance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getAttendaceLockingPeriod
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 createAttendanceLockingPeriod
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 23
 removeAttendanceLockingPeriod
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 checkAttendanceLockingPeriod
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 22
 checkAttendanceReconfirm
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 markAllAbsentPresent
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 checkAttendanceMarkedForExam
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getMarkedAttendanceByStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 getAttendanceMarkedHoursByStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 createAttendanceDeleteLog
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 deleteAttendance
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 40
 deleteAttendanceTemporary
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 27
 deleteAttendanceConfirm
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 23
 deleteAttendanceConfirmTemporary
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 23
 getConsolidatedattendanceDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 getAttendanceTempConfirmedStaffDetails
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 getStudentCoincidenceAttendanceTemp
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 34
 getStudentCoincidenceAttendance
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 34
 addAttendanceConfirmTemp
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getUnmarkedStudents
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 28
 addAttendanceTemp
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 43
 getStudentsFromAttendanceTemp
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 55
 getStudentsFromAttendance
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 32
 updateAttendanceConfirmTemp
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getAttendanceConfirmedForAllbatchStaffDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 getUnmarkedStudentAfterConfirm
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 25
 getAttendanceTakenHours
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 19
 getAssignedAttendanceTakenHours
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 19
 getTotalAttendanceTakenHours
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 19
 getSuspendedHourCount
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 hasAttendanceModifyPrivillege
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 getPseudoSubjectAttendanceDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 54
 getPseudoSubjectAttendanceMarkedDates
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getAbsenteesListPerDayBySbsIds
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 getStudentAttendanceDetailsSubjectWise
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 37
 getStudentAttendanceDetailsSubjectWiseForCondonation
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 23
 getStudentAttendanceDetailsForASubject
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 39
 getAbsentHoursOfAStudentByDate
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 16
 getAttendanceMarkedPseudoSubjectsByDate
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getPseudoSubjectAbsenteesCountByDate
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 31
 getStudentAttendancePercentageHourWise
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getStudentExpectedAttendancePercentageHourWise
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 getNoOfHoursByBatch
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getNoOfHoursAttendedByStudentId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 getStudentAttDetailsInDateRange
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 getAttendanceMarkedDates
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getStudentAttDetailsBySession
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 126
 getStudentCoincidenceAttendanceForSameSbsBySubbatch
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 20
 isAttendanceMarked
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 isAttendanceMarkedforHour
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 38
 addUpdateAttendanceRule
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 25
 getUnmarkedHourAndDateDetails
0.00% covered (danger)
0.00%
0 / 1
272.00
0.00% covered (danger)
0.00%
0 / 64
 getUnmarkedHourAndDate
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 isSuspendedHourForBatch
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 getSuspendedHoursBetweenDates
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 checkSbsIDForMarkedStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getTotalHourDetailsOfFaculty
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 17
 checkSbsID
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getMarkedHourDetailsWithFaculty
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 44
 getStudentsAttendanceByDate
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 20
 getCollegeDefinedHours
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 staffPrivilege
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 validateDutyLeaveRemarksObject
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 9
 addDutyLeaveRemarks
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 deleteDutyLeaveRemarks
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 updateDutyLeaveRemarks
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 16
 getAllDutyLeaveRemarks
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 getDutyLeaveRemarksDetailsForStudents
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 grantDutyLeaveHourWise
0.00% covered (danger)
0.00%
0 / 1
210.00
0.00% covered (danger)
0.00%
0 / 38
 getLeaveTypeIdOfDutyLeave
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 getAllLeaveTypeIdsOfDutyLeave
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 18
 getAttendanceEditPrivilege
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 createAttendanceEditPrivilege
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 16
 deleteAttendanceEditPrivilege
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getAllAttendanceEditPrivilege
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 deleteStudentsFromAttendanceTempOtherBatch
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 addAttendanceLog
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 removeAttendanceLog
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 18
 addAttendanceLogFromTimeTable
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 22
 updateAttendanceConfirmLog
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 updateAttendanceMarkedForAllLog
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 17
 getUnmarkedAttendanceLog
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 removeMarkedAttendanceLog
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 addAttendanceLogAfterAttendanceDelete
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 isUnmarkedStudentAfterConfirm
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 24
 getLockPeriodDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getAttendanceConfirmedStaffDetailsForAGivenDateRange
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 27
 getAttendanceConfirmedDetailsForAGivenDateRange
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 30
 getSubjectWiseStudentAttendanceWithAttendanceRulesConsidered
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 22
 getSubjectAttendanceInDateRange
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 82
 getStudentListForAllPseudoSubjectsInAnAttendanceHour
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 44
 isAttendanceConfirmed
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 markAllPresentOrAbsentByBatch
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 31
 markAllPresentOrAbsentBySubBatch
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 31
 confirmAttendance
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 getAttendanceDetailsByStudentDateHour
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 getAttendanceDetailsByStudentIdAttendanceDate
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 41
 deactivateAttendanceRule
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 activateAttendanceRule
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 deleteAttendanceRuleByBatchIDAndSemID
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 getAttendancePercentageBySubjectIDAndStudentID
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 89
 updateStudentAttandanceDLWithStudentID
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 24
 addAttndanceFromTemp
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 isAttendanceMarkedForAllStudent
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 32
 isAttendanceMarkedForPseudoSubject
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 getStudentAttendancePercentageSemesterwise
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 19
 addAttendanceAfterSemesterRegistrationByStudentId
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 36
 removeAttendanceAfterSubbatchRemoveByStudentId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getCurrentAttendanceRule
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 18
 academicAuditReport
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 confirmHourAttendance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 47
 getStudentAttendancePercentageDetails
0.00% covered (danger)
0.00%
0 / 1
506.00
0.00% covered (danger)
0.00%
0 / 94
 getAttendanceDates
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 43
 getAttendanceDataOfStudent
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 106
 getStudentsAttendanceBySbsId
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 67
 getHourAttendedStudents
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 28
 getStudentLastAttendance
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 getStudentAttendance
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 20
 getTemoraryAttendanceDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 9
 saveBatchAbsenteespercentByBatch
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 19
 getStudentsAttendanceByRequest
0.00% covered (danger)
0.00%
0 / 1
1260.00
0.00% covered (danger)
0.00%
0 / 104
 getStudentsAttendance
0.00% covered (danger)
0.00%
0 / 1
462.00
0.00% covered (danger)
0.00%
0 / 81
 getPseudoSubjectAttendanceMarkedStudents
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 27
 checkAttendanceDetailsByRequest
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 22
 getStudentAttendanceDetailsBySbsIdAndDateRange
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 25
 getStaffAttendanceHours
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 15
 createAttendanceDeleteLogFromErpAdmin
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 deleteAttendanceFromErpAdmin
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 40
 deleteAttendanceTemporaryFromErpAdmin
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 27
 generateSubjectWiseAbsenteesAttendanceDetails
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 31
 getAttendanceDetailsOfStudent
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 98
 grantStudentAttendance
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 44
 getAStudentAttDetailsInDateRange
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 55
 deleteAttendanceByattendanceId
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 11
 getAttendanceDetailsByRequest
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 24
 academicAuditReportForStaff
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 32
 getSubjectWiseAttendanceDetails
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 116
 getAttendanceDetailsApi
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 48
 getStudentsDaywiseAttendance
0.00% covered (danger)
0.00%
0 / 1
756.00
0.00% covered (danger)
0.00%
0 / 131
 getStudentsHourwiseAttendanceForApi
0.00% covered (danger)
0.00%
0 / 1
1260.00
0.00% covered (danger)
0.00%
0 / 125
 getHoursDetailsFromAttendanceOfStudent
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 20
 getStudentAttendanceDetailsByStudent
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 10
 giveAttendanceForStudent
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 CheckForSubjectPlanner
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 32
 CheckForSubjectPlannerInActualPlan
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 42
 getAttendanceExistingOrNot
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 12
 blockAttendanceForStudent
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 getBlockedDetailsByStudentID
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 removeBlockAttendance
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 MultiBlockAttendance
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 42
 getDutyLeaveDetailsByStudentID
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 114
<?php
namespace com\linways\core\ams\professional\service;
use com\linways\core\ams\professional\dto\Hour;
use com\linways\core\ams\professional\dto\Timetable;
use com\linways\core\ams\professional\dto\Attendance;
use com\linways\core\ams\professional\dto\BatchTimetable;
use com\linways\core\ams\professional\dto\BlockAttendance;
use com\linways\core\ams\professional\dto\SettingsConstents;
use com\linways\core\ams\professional\dto\UnBlockAttendance;
use com\linways\core\ams\professional\request\CheckAttendanceConfirmedRequest;
use com\linways\core\ams\professional\request\ConfirmAttendanceRequest;
use com\linways\core\ams\professional\request\MarkAllAttendanceRequest;
use com\linways\core\ams\professional\service\StudentService;
use com\linways\core\ams\professional\service\BatchService;
use com\linways\core\ams\professional\dto\AttendanceEditPrivilege;
use com\linways\core\ams\professional\dto\AttendanceLockingPeriod;
use com\linways\core\ams\professional\mapper\AttendanceServiceMapper;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\request\SearchAttndceBlkdStudentRequest;
use com\linways\core\ams\professional\response\SearchAttndceBlkdStudentResponse;
use com\linways\core\ams\professional\request\GetAbsentHoursOfAStudentByDateRequest;
use com\linways\core\ams\professional\dto\AttendanceLog;
use com\linways\core\ams\professional\util\CommonUtil;
use com\linways\core\ams\professional\service\OnlineInteractiveClassService;
use stdClass;
class AttendanceService extends BaseService
{
    // /Condition 1 - Presence of a static member variable
    private static $_instance = null;
    private $mapper = [];
    // /Condition 2 - Locked down the constructor
    private function __construct()
    {
        $this->mapper = AttendanceServiceMapper::getInstance()->getMapper();
    }
    // Prevent any oustide instantiation of this class
    // /Condition 3 - Prevent any object or instance of that class to be cloned
    private function __clone()
    {
    }
    // Prevent any copy of this object
    // /Condition 4 - Have a single globally accessible static method
    public static function getInstance()
    {
        if (!is_object(self::$_instance)) // or if( is_null(self::$_instance) ) or if( self::$_instance == null )
        {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    /**
     * Get Approved Duty Leave students of given date annd hour
     *
     * @param int $batchID
     * @param int $semID
     * @param int $hour
     * @param string $attendanceDate
     * @param int $subbatchID
     */
    public function getDLApprovedStudents($batchID, $subbatchID, $semID, $hour, $attendanceDate)
    {
        $students = [];
        $sql = "select distinct sa.studentId,sa.studentName from student_leave_application sla
            inner join student_leave_type slt on slt.id = sla.leave_type_Id and slt.isDL = 1 and slt.isActive=1
            inner join studentaccount sa on sa.studentId =sla.student_Id
            inner join attendance a on a.studentId = sla.student_Id
            inner join attendance_confirm ac on ac.sbsId = a.sbsId and ac.batchId = a.batchId and ac.semId = a.semId
            and ac.hour = a.hour
            where a.batchID=$batchID
            and a.semID=$semID
            and a.hour=$hour
            and a.attendanceDate='$attendanceDate'
            and ac.subbatchID = $subbatchID
            and find_in_set('$hour',sla.session_key) > 0
            and sla.status = 'APPROVED'
            and '$attendanceDate' between sla.start_date AND end_date";
        try {
            $students = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $students;
    }
    /**
     *
     * @param string $studentsIds
     *            - comma separated string
     * @param int $batchID
     * @param int $subbatchID
     * @param int $semID
     * @param int $hour
     * @param string $attendanceDate
     */
    public function applyDLToAttendance($studentIds, $batchID, $subbatchID, $semID, $hour, $attendanceDate)
    {
        if ($studentIds != null && $studentIds != "") {
            $sql = "Update attendance set isAbsent = 2 where  batchID=$batchID
            and semID=$semID
            and hour=$hour
            and attendanceDate='$attendanceDate' and studentId IN ($studentIds);
";
            try {
                $this->executeQuery($sql);
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
        }
        return true;
    }
    /**
     * setStudentDLToAttendance
     *
     * @param int $batchID
     * @param int $subbatchID
     * @param int $semID
     * @param int $hour
     * @param string $attendanceDate
     */
    public function setStudentDLToAttendance($batchID, $subbatchID, $semID, $hour, $attendanceDate)
    {
        // Get DL approved students and DL to attendance table
        $DLApprovedStudents = $this->getDLApprovedStudents($batchID, $subbatchID, $semID, $hour, $attendanceDate);
        $studentIds = "";
        if ($DLApprovedStudents != null && count($DLApprovedStudents) > 0) {
            foreach ($DLApprovedStudents as $student) {
                if ($studentIds == "") {
                    $studentIds = $student->studentId;
                } else {
                    $studentIds .= "," . $student->studentId;
                }
            }
            try {
                $this->applyDLToAttendance($studentIds, $batchID, $subbatchID, $semID, $hour, $attendanceDate);
            } catch (\Exception $e) {
                throw $e;
            }
        }
        return $DLApprovedStudents;
    }
    /**
     * Search Subject
     *
     * @param SearchAttndceBlkdStudentRequest $searchAttndceBlkdStudentRequest
     * @return $searchAttndceBlkdStudentResponse
     */
    public function searchAttndceBlkdStudentRequest($searchAttndceBlkdStudentRequest)
    {
        $searchAttndceBlkdStudentResponse = new SearchAttndceBlkdStudentResponse();
        $explodedhours = '';
        if ($searchAttndceBlkdStudentRequest != NULL) {
            $sql_count = "SELECT count(sta.studentID) AS totalRecord FROM studentaccount sta
                            INNER JOIN attendance_blocked_students atbs ON sta.studentID = atbs.studentId
                                WHERE sta.batchID = '$searchAttndceBlkdStudentRequest->batchId'";
            $sql = "SELECT sta.studentID, sta.studentName, sta.rollNo, sta.admissionNo, atbs.date, atbs.hours FROM studentaccount sta
                    INNER JOIN attendance_blocked_students atbs ON sta.studentID = atbs.studentId
                                WHERE sta.batchID = '$searchAttndceBlkdStudentRequest->batchId'";
            if ($searchAttndceBlkdStudentRequest->studentName) {
                $sql_cond .= " AND sta.studentName like '%$searchAttndceBlkdStudentRequest->studentName%'";
            }
            if ($searchAttndceBlkdStudentRequest->rollNo) {
                $sql_cond .= " AND sta.rollNo like '%$searchAttndceBlkdStudentRequest->rollNo%'";
            }
            if ($searchAttndceBlkdStudentRequest->admNo) {
                $sql_cond .= " AND sta.admissionNo like '%$searchAttndceBlkdStudentRequest->admNo%'";
            }
            if ($searchAttndceBlkdStudentRequest->fromDate) {
                $sql_cond .= " AND atbs.date >= '$searchAttndceBlkdStudentRequest->fromDate'";
            }
            if ($searchAttndceBlkdStudentRequest->toDate) {
                $sql_cond .= " AND atbs.date <= '$searchAttndceBlkdStudentRequest->toDate'";
            }
            if ($searchAttndceBlkdStudentRequest->hours && $searchAttndceBlkdStudentRequest->hours != 0) {
                $explodedhours = explode(',', $searchAttndceBlkdStudentRequest->hours);
                $sql_cond .= " AND ";
                $i = 0;
                foreach ($explodedhours as $hour) {
                    $sql_cond .= " FIND_IN_SET('" . $hour . "',hours)";
                    $i++;
                    if (sizeof($explodedhours) != $i) {
                        $sql_cond .= " OR";
                    }
                }
            }
            $sql_cond .= "order by atbs.date DESC ";
            $sql_count .= $sql_cond;
            $totalRecordResult = $this->executeQueryForObject($sql_count);
            $searchAttndceBlkdStudentResponse->totalRecords = $totalRecordResult->totalRecord;
            if ($searchAttndceBlkdStudentRequest->export) {
                $searchAttndceBlkdStudentRequest->endIndex = $searchAttndceBlkdStudentResponse->totalRecords;
            }
            $sql .= $sql_cond . "LIMIT $searchAttndceBlkdStudentRequest->startIndex,$searchAttndceBlkdStudentRequest->endIndex";
            $searchAttndceBlkdStudentResponse->students = $this->executeQueryForList($sql);
        }
        return $searchAttndceBlkdStudentResponse;
    }
    /**
     * Get attendance hours
     *
     * @return $attendanceHours
     */
    public function getAttendanceHours()
    {
        global $ATTENDANCE_HOURS;
        $attendanceHours = [];
        for ($i = 1; $i <= $ATTENDANCE_HOURS; $i++) {
            $attendanceHours[] = $i;
        }
        return $attendanceHours;
    }
    /**
     * Update isBlocked of blocked students while marking attendance
     *
     * @param string $attendanceDate
     * @param int $hour
     * @param int $batchID
     * @param int $semID
     */
    public function blockAttendance($attendanceDate, $hour, $batchID, $semID)
    {
        $sql = "UPDATE attendance SET isBlocked=1 WHERE attendanceDate='$attendanceDate' AND hour=$hour AND batchID=$batchID AND semID=$semID
                AND studentID IN(SELECT studentID FROM attendance_blocked_students WHERE date='$attendanceDate' AND FIND_IN_SET('" . $hour . "',hours))";
        $this->executeQuery($sql);
    }
    /**
     * Process the request for blocking attendance of students
     *
     * @param BlockAttendance $blockAttendanceList
     */
    public function blockStudentAttendance($blockAttendanceList)
    {
        $explodedBlockedHours = [];
        $resultHours = [];
        $staffID =  $_SESSION['adminID'] ? $_SESSION['adminID'] : $_SESSION['staffID'];
        foreach ($blockAttendanceList as $blockAttendance) {
            $blockedHours = $this->isStudentBlockedByDate($blockAttendance->studentId, $blockAttendance->date);
            if ($blockedHours != NULL) // already blocked hours at same date
            {
                $explodedhours = explode(',', $blockAttendance->hours);
                $explodedBlockedHours = explode(',', $blockedHours->hours);
                $resultHours = array_unique(array_merge($explodedhours, $explodedBlockedHours));
                $sql_update = "UPDATE attendance_blocked_students SET hours='" . implode(',', $resultHours) . "' WHERE studentId= $blockAttendance->studentId AND date='$blockAttendance->date'";
                $sqlLogUpdate = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($blockAttendance->studentId,'$blockAttendance->date','".implode(',', $resultHours)."','UPDATE','ERP_HOD_TUTOR','$staffID')";
                $this->executeQuery($sql_update);
                $this->executeQuery($sqlLogUpdate);
                $this->updateBlockedAttendance($blockAttendance->studentId, $blockAttendance->date, $blockedHours->hours);
            } else {
                // hours of this date is not blocked
                {
                    $sql_insert = "INSERT INTO attendance_blocked_students(studentId,date,hours) VALUES($blockAttendance->studentId,'$blockAttendance->date','$blockAttendance->hours')";
                    $sqlLogInsert = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($blockAttendance->studentId,'$blockAttendance->date','$blockAttendance->hours','INSERT','ERP_HOD_TUTOR','$staffID')";
                    $this->executeQuery($sql_insert);
                    $this->executeQuery($sqlLogInsert);
                    $this->updateBlockedAttendance($blockAttendance->studentId, $blockAttendance->date, $blockAttendance->hours);
                }
            }
            reset($explodedBlockedHours);
            reset($resultHours);
        }
    }
    /**
     * Check whether a student's attendance is blocked.
     * if yes, returns hours.
     * @param int $studentId
     * @param string $date
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function isStudentBlockedByDate($studentId, $date)
    {
        $sql_chk = "SELECT hours FROM attendance_blocked_students where studentId = $studentId AND date='$date'";
        return $this->executeQueryForObject($sql_chk);
    }
    /**
     * update blocked attendance
     * @param int $studentId
     * @param string $date
     * @param int $hours
     */
    public function updateBlockedAttendance($studentId, $date, $hours)
    {
        $sql = "UPDATE attendance SET isBlocked=1 WHERE attendanceDate='$date' AND hour IN($hours)  AND studentID=$studentId";
        $this->executeQuery($sql);
    }
    /**
     * Process the request for unblocking attendance of students
     * @param UnBlockAttendance $unBlockAttendanceList
     */
    public function unBlockStudentAttendance(array $UnBlockAttendanceList)
    {
        $explodedBlockedHours = [];
        $resultHours = [];
        $staffID =  $_SESSION['adminID'] ? $_SESSION['adminID'] : $_SESSION['staffID'];
        foreach ($UnBlockAttendanceList as $unBlockStudentAttendance) {
            $blockedHours = $this->isStudentBlockedByDate($unBlockStudentAttendance->studentId, $unBlockStudentAttendance->date);
            if ($blockedHours != NULL) {
                $explodedhours = explode(',', $unBlockStudentAttendance->hours);
                $explodedBlockedHours = explode(',', $blockedHours->hours);
                $resultHours = array_diff($explodedBlockedHours, $explodedhours);
                if ($resultHours == NULL) {
                    $sql_update = "DELETE FROM attendance_blocked_students WHERE studentId= $unBlockStudentAttendance->studentId AND date='$unBlockStudentAttendance->date'";
                    $sqlLogDelete = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($unBlockStudentAttendance->studentId,'$unBlockStudentAttendance->date','".implode(',', $resultHours)."','DELETE','ERP_HOD_TUTOR','$staffID')";
                    $this->executeQuery($sql_update);
                    $this->executeQuery($sqlLogDelete);
                } else {
                    $sql_update = "UPDATE attendance_blocked_students SET hours='" . implode(',', $resultHours) . "' WHERE studentId= $unBlockStudentAttendance->studentId AND date='$unBlockStudentAttendance->date'";
                    $sqlLogUpdate = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($unBlockStudentAttendance->studentId,'$unBlockStudentAttendance->date','".implode(',', $resultHours)."','UPDATE','ERP_HOD_TUTOR','$staffID')";
                    $this->executeQuery($sql_update);
                    $this->executeQuery($sqlLogUpdate);
                }
                $this->updateUnblockedAttendance($unBlockStudentAttendance->studentId, $unBlockStudentAttendance->date, $unBlockStudentAttendance->hours);
            }
            reset($explodedBlockedHours);
            reset($resultHours);
        }
    }
    /**
     * update unblocked attendance
     * @param int $studentId
     * @param string $date
     * @param int $hours
     */
    public function updateUnblockedAttendance($studentId, $date, $hours)
    {
        $sql = "UPDATE attendance SET isBlocked=0 WHERE attendanceDate='$date' AND hour IN($hours)  AND studentID=$studentId";
        $this->executeQuery($sql);
    }
    /**
     * get attendance count of a subject by date
     * @param string $date
     * @param int $hour
     * @param int $batchId
     * @param int $semId
     * @param string $fromJoiningDate
     * @param string $failed
     * @return int $attendanceCount
     * @throws ProfessionalException
     */
    public function getAttendanceCount($date, $hour, $batchId, $semId, $fromJoiningDate = FALSE, $failed = FALSE, $isAbsent = FALSE, $subbatchId = FALSE)
    {
        $attendanceCount = 0;
        if (!$failed) {
            $sql = "SELECT count(studentID) as studentCount FROM attendance WHERE  attendanceDate='" . date("Y-m-d", strtotime($date)) . "' AND hour=$hour AND batchID=$batchId AND semID=$semId ";
        } else {
            $sql = "SELECT count(at.studentID) as studentCount FROM attendance at INNER JOIN studentaccount sa ON sa.studentID=at.studentID AND sa.batchID=at.batchID WHERE  at.attendanceDate='" . date("Y-m-d", strtotime($date)) . "' AND at.hour=$hour AND at.batchID=$batchId AND at.semID=$semId ";
        }
        if ($fromJoiningDate) {
            $sql .= "AND sa.studentJoindate <= '" . date("Y-m-d", strtotime($date)) . "'";
        }
        if($isAbsent){
            $sql .= " AND isAbsent=0";
        }
        if($subbatchId){
            $sql .= " AND sbsID = $subbatchId";
        }
        try {
            $attendanceCount = $this->executeQueryForObject($sql)->studentCount;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceCount;
    }
    /**
     * get  attendance rule defined by hod using batchId and semId
     * @param int $batchId
     * @param int $semId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceRule($batchId, $semId)
    {
        $attendanceRules = NULL;
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sql = "SELECT batchID,semID,dateOfjoining,morninghours,classStartsFrom,classEnds,isActive,halfdayHourCount,fulldayHourCount FROM attendance_rules WHERE batchID=$batchId AND semID=$semId";
        try {
            $attendanceRules = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceRules;
    }
    /**
     * check attendance date before attendance limit or not
     * @param BatchTimetable $batchTimetable
     * @return boolean
     * @throws ProfessionalException
     */
    public function checkAttendanceLimitValid($batchTimetable, $centralised = FALSE)
    {
        $batchTimetable = $this->realEscapeObject($batchTimetable);
        $centralised = $this->realEscapeString($centralised);
        $limit = 0;
        $attendancelimitFlag = NULL;
        $sql = "SELECT attendancelimit, lockingType, markingPeriodType FROM attendance_limit WHERE batchID = " . $batchTimetable->batchId . "";
        try {
            if ($centralised) {
                $enable = CommonService::getInstance()->getSettings(SettingsConstents::ATTENDANCE_SETTINGS, SettingsConstents::CENTRALISED_ATTENDANCE_LIMIT_ENABLE);
                $limit = CommonService::getInstance()->getSettings(SettingsConstents::ATTENDANCE_SETTINGS, SettingsConstents::CENTRALISED_ATTENDANCE_LIMIT);
                $lockingType = CommonService::getInstance()->getSettings(SettingsConstents::ATTENDANCE_SETTINGS, SettingsConstents::CENTRALISED_ATTENDANCE_TYPE);
                $markingPeriodType = CommonService::getInstance()->getSettings(SettingsConstents::ATTENDANCE_SETTINGS, SettingsConstents::CENTRALISED_ATTENDANCE_MARKING_PERIOD_TYPE);
            } else {
                $attendancelimit = $this->executeQueryForObject($sql);
                if ($attendancelimit) {
                    $enable = true;
                    $limit = $attendancelimit->attendancelimit;
                    $lockingType = $attendancelimit->lockingType;
                    $markingPeriodType = $attendancelimit->markingPeriodType;
                } else {
                    $enable = false;
                }
            }
            if ($enable) {
                $attendanceDate = $batchTimetable->timetableDate;
                $hourDetails = TimetableService::getInstance()->getHourDetails($batchTimetable);
                // Converting attendanceLimit to seconds
                $attendanceLimitTime = 0;
                $lockingType = strtoupper($lockingType);
                if ($lockingType == 'DAY') {
                    $attendanceLimitTime = $limit * 86400;
                } else if ($lockingType == 'TIME') {
                    if (!$hourDetails->stratTime) {
                        return Attendance::ATTENDANCE_TIME_NOT_SET;
                    }
                    $attendanceLimitTime = $limit * 60;
                }
                // Converting attendanceLimit to seconds Ends
                $limitStartTime = 0;
                $markingPeriodType = strtoupper($markingPeriodType);
                if ($markingPeriodType == 'DAY') {
                    // To get time as 11:59:59 PM - Add 1 day and substract 1 second to the time of a day. 
                    $limitStartTime = strtotime('+1 day', strtotime($attendanceDate)) - 1;
                } else if ($markingPeriodType == 'WEEK') {
                    // To get time as Sunday 11:59:59 PM - substract 1 second from next Monday 12:00:00 AM
                    $limitStartTime = strtotime("next monday", strtotime($attendanceDate)) - 1;
                } else if ($markingPeriodType == 'MONTH') {
                    // To get last day of a month 11:59:59 PM - Substract 1 second from the first day of next month 12:00:00 AM
                    $monthLastDate = date('Y-m-t', strtotime($attendanceDate));
                    $limitStartTime = strtotime('+1 day', strtotime($monthLastDate)) - 1;
                } else {
                    // $markingPeriodType == 'HOUR'
                    if ($lockingType == 'DAY' && ($limit == 0 || !$hourDetails->stratTime)) {
                        // Attendance can be marked till 11:59:59 PM of that attendance day
                        $limitStartTime = strtotime('+1 day', strtotime($attendanceDate)) - 1;
                        // Since $attendanceLimitTime = 0; we will set $limitStartTime to 11:59:59 PM
                    }
                    // Get timetable hour start time
                    // If start time is not given and lockingType = 'TIME' then time will be taken from midnight 12:00 am and attendance cannot be marked 
                    else {
                        $limitStartTime = strtotime($attendanceDate . " " . $hourDetails->stratTime);
                    }
                }
                $currentTime = time();
                $lastDateWithoutLock = $limitStartTime + $attendanceLimitTime;
                if ($currentTime <= $lastDateWithoutLock) {
                    $attendancelimitFlag = Attendance::ATTENDANCE_LIMIT_NOT_EXPIRED;
                } else {
                    $attendancelimitFlag = Attendance::ATTENDANCE_LIMIT_EXPIRED;
                }
            } else {
                $attendancelimitFlag = Attendance::ATTENDANCE_LIMIT_NOT_EXPIRED;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendancelimitFlag;
    }
    /**
     * get details of attendance confirmed staff
     * @param int $batchId
     * @param int $semId
     * @param int $hour
     * @param string $attendanceDate
     * @param int $subbatchId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceConfirmedStaffDetails($batchId, $semId, $hour, $attendanceDate, $subbatchId = 0, $sbsId = null)
    {
        $staffDetails = NULL;
        $sql = "SELECT sa.staffID, ac.subbatchID, if(sb.subbatchName !='',sb.subbatchName,'All') as subbatchName
, sr.sbsID, sa.staffName, ac.confirmedDate, ac.exam_id as examId, subj.subjectDesc, subj.subjectName,ac.remarks FROM attendance_confirm ac INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID INNER JOIN subjects subj ON subj.subjectID=sr.subjectID INNER JOIN staffaccounts sa ON sa.staffID=sr.staffID LEFT JOIN subbatches sb ON sb.subbatchID=ac.subbatchID WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.attendanceDate='" . date('Y-m-d', strtotime($attendanceDate)) . "'";
        if ($subbatchId) {
            $sql .= " AND ac.subbatchID IN (" . $subbatchId . ",0)";
        }
        if (!empty($hour)) {
            $sql .= " AND ac.hour='$hour";
        }
        if ($sbsId) {
            $sql .= " AND ac.sbsID = '" . $sbsId . "'";
        }
        try {
            $staffDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $staffDetails;
    }
    /**
     * update student attendance
     * @param Attendance $attentance
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function updateStudentsAttendance($attentance)
    {
        $sql = "UPDATE attendance  SET isAbsent=$attentance->isAbsent, updatedBy=$attentance->updatedBy, updatedDate=utc_timestamp() WHERE attendanceDate='" . date('Y-m-d', strtotime($attentance->attendanceDate)) . "' AND hour=$attentance->hour AND batchID=$attentance->batchID AND semID=$attentance->semID AND sbsID=$attentance->sbsID AND studentID=$attentance->studentID";
        try {
            
            $sql_remarks = "UPDATE attendance_confirm SET remarks = '$attentance->remarks' WHERE attendanceDate='" . date('Y-m-d', strtotime($attentance->attendanceDate)) . "' AND hour=$attentance->hour AND batchID=$attentance->batchID AND semID=$attentance->semID AND sbsID=$attentance->sbsID";  
            $this->executeQueryForObject($sql_remarks);
            
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update student temporary attendance
     * @param Attendance $attentance
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function updateStudentsTempAttendance($attentance)
    {
        $sql = "UPDATE attendance_temporary  SET isAbsent=$attentance->isAbsent WHERE attendanceDate='" . date('Y-m-d', strtotime($attentance->attendanceDate)) . "' AND hour=$attentance->hour AND batchID=$attentance->batchID AND semID=$attentance->semID AND sbsID=$attentance->sbsID AND studentID=$attentance->studentID";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getAttendaceLockingPeriod($deptId)
    {
        $batchDetails = NULL;
        $sql = "SELECT bth.batchName, bth.batchStartYear, bth.batchEndYear, bth.batchID, al.attendanceLockingLimit FROM batches bth LEFT JOIN attendanceLockingPeriod al ON al.batchID=bth.batchID WHERE bth.batchHide=0 AND bth.batchName !='failed' AND bth.deptID=" . $deptId;
        try {
            $batchDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $batchDetails;
    }
    /**
     * create attendance locking period
     * @param AttendanceLockingPeriod $attendanceLockingPeriod
     * @throws ProfessionalException
     */
    public function createAttendanceLockingPeriod($attendanceLockingPeriodList)
    {
        $sql = "INSERT INTO attendanceLockingPeriod
                (
                    deptId,
                    batchId,
                    attendanceLockingLimit,
                    createdBy,
                    createdDate,
                    updatedBy,
                    updatedDate
                )
                VALUES ";
        $value = [];
        foreach ($attendanceLockingPeriodList as $attendanceLockingPeriod) {
            $value[] = "($attendanceLockingPeriod->deptId,$attendanceLockingPeriod->batchId,$attendanceLockingPeriod->attendanceLockingLimit,$attendanceLockingPeriod->createdBy,utc_timestamp(),$attendanceLockingPeriod->updatedBy,utc_timestamp())";
        }
        $sql .= implode(',', $value);
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete from attendance locking period by department
     * @param int $deptId
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function removeAttendanceLockingPeriod($deptId)
    {
        $sql = "DELETE FROM attendanceLockingPeriod WHERE deptId=$deptId";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * check attendance date before attendance limit or not
     * @param int $batchId
     * @param string $attendanceDate
     * @return boolean
     * @throws ProfessionalException
     */
    public function checkAttendanceLockingPeriod($batchId, $attendanceDate)
    {
        $attendancelimit = 0;
        $attendancelimitFlag = FALSE;
        $sql = "SELECT attendanceLockingLimit FROM attendanceLockingPeriod WHERE batchID = $batchId";
        try {
            $attendancelimit = $this->executeQueryForObject($sql)->attendanceLockingLimit;
            if ($attendancelimit != null) {
                $date = date("Y-m-d");
                $newdate = strtotime("-" . $attendancelimit . " day", strtotime($date));
                $newdate = date("Y-m-d", $newdate);
                $attendanceDate = date("Y-m-d", strtotime($attendanceDate));
                if ($newdate <= $attendanceDate) {
                    $attendancelimitFlag = TRUE;
                } else {
                    $attendancelimitFlag = FALSE;
                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendancelimitFlag;
    }
    /**
     * check attendance reconfirm enabled for a batch or not
     * @param int $batchId
     * @return boolean $isReconfirmEnabled;
     * @throws ProfessionalException
     */
    public function checkAttendanceReconfirm($batchId)
    {
        $isReconfirmEnabled = FALSE;
        $sql = "SELECT if(attendanceLockingLimit>=0,TRUE,FALSE) as reconfirmEnabled FROM attendanceLockingPeriod WHERE batchID=$batchId";
        try {
            $isReconfirmEnabled = $this->executeQueryForObject($sql)->reconfirmEnabled;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $isReconfirmEnabled;
    }
    /**
     * make all batch attendance absent or present in temperory
     * @param int $isAbsent
     * @param int $batchId
     * @param int $semId
     * @param int $subbatchId
     * @param string $attendanceDate
     * @param int $hour
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function markAllAbsentPresent($isAbsent, $batchId, $semId, $subbatchId, $attendanceDate, $hour)
    {
        $sql = "UPDATE attendance_temporary SET isAbsent=$isAbsent WHERE batchID=$batchId AND hour=$hour AND attendanceDate='$attendanceDate' AND semID=$semId AND subbatchID=$subbatchId";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * check attendance is marked for exam or not
     * if true exam attendance
     * if false attendance is not marked for exam
     * @param int $batchId
     * @param int $subbatchId
     * @param string $attendDate
     * @param int $hour
     * @throws ProfessionalException
     */
    public function checkAttendanceMarkedForExam($batchId, $subbatchId, $attendDate, $hour)
    {
        $flag = FALSE;
        $sql = "select exam_id from attendance_confirm where batchID=$batchId and subbatchID=$subbatchId and attendanceDate='" . date('Y-m-d', strtotime($attendDate)) . "' and hour=$hour";
        try {
            $examId = $this->executeQueryForObject($sql)->exam_id;
            if ($examId) {
                $flag = TRUE;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $flag;
    }
    /**
     * Get attendance dates marked by a staff for a batch
     * @param int $batchId
     * @param int $semId
     * @param int $staffId
     * @param string $fromday
     * @param string $today
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getMarkedAttendanceByStaff($batchId, $semId, $sbsId, $fromday, $today)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sbsId = $this->realEscapeString($sbsId);
        $fromday = $this->realEscapeString($fromday);
        $today = $this->realEscapeString($today);
        $sql = "select DISTINCT(attendanceDate) from attendance_confirm where semID= $semId and batchID=$batchId and attendanceDate BETWEEN '$fromday' AND '$today' and sbsID = $sbsId ORDER BY attendanceDate";
        try {
            $attendanceDates = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDates;
    }
    /**
     * Get attendance hours marked by a staff for a batch
     * @param int $batchId
     * @param int $semId
     * @param int $staffId
     * @param string $attendanceDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceMarkedHoursByStaff($batchId, $semId, $sbsId, $attendanceDate)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $sbsId = $this->realEscapeString($sbsId);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $sql = "select DISTINCT(hour) from attendance_confirm where  attendanceDate='$attendanceDate' and batchID= $batchId  and semID= $semId and sbsID = $sbsId";
        try {
            $attendanceHours = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceHours;
    }
    /**
     * Create attendance delete log
     * @param Attendance $attendanceDetails
     * @param string $subj_attendance
     * @return boolean
     * @throws ProfessionalException
     */
    public function createAttendanceDeleteLog($attendanceDetails, $subj_attendance = null)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $staffId = $this->realEscapeString($attendanceDetails->staffID);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $attendanceDetails->hour ? $this->realEscapeString($attendanceDetails->hour) : 'null';
        $sql = "insert into delete_attendance_log (staffID,batchID,semID,attendanceDate,hour) values ($staffId$batchId$semId, '" . $attendanceDate . "', $hour)";
        try {
            $this->executeQueryForObject($sql);
            $this->deleteAttendance($attendanceDetails);
            $this->deleteAttendanceConfirm($attendanceDetails);
            if ($subj_attendance) {
                $this->deleteAttendanceConfirmTemporary($attendanceDetails);
                $this->deleteAttendanceTemporary($attendanceDetails);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * Delete attendance
     * @param Attendance $attendanceDetails
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function deleteAttendance($attendanceDetails)
    {
        $attendanceDetails = $this->realEscapeObject($attendanceDetails);
        $batchId = $attendanceDetails->batchID;
        $semId = $attendanceDetails->semID;
        $staffId = $attendanceDetails->staffID;
        $attendanceDate = $attendanceDetails->attendanceDate;
        $hour = $attendanceDetails->hour;
        $sbsId = $attendanceDetails->sbsID;
        if (!empty($staffId)) {
            $sql_staff = " AND staffID = $staffId";
        }
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $confirmedStaffDetails = $this->getAttendanceConfirmedStaffDetails($batchId, $semId, $hour, $attendanceDate, 0, $sbsId);
        if (count($confirmedStaffDetails) == 1) {
            $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs";
        } else {
            if ($attendanceDetails->subbatchId != NULL) {
                if ($attendanceDetails->subbatchId == 0) {
                    $subbatchIds = array_map(function ($obj) {
                        return $obj->subbatchID;
                    }, $confirmedStaffDetails);
                    $subbatchIds = array_unique($subbatchIds);
                    $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs AND studentID NOT IN(select studentID from subbatch_student where subbatchID IN(" . implode(',', $subbatchIds) . "))";
                } else {
                    $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs AND studentID IN(select studentID from subbatch_student where subbatchID=$attendanceDetails->subbatchId)";
                }
            } else {
                $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs";
            }
        }
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Delete from attendance_temporary
     * @param Attendance $attendanceDetails
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function deleteAttendanceTemporary($attendanceDetails)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $staffId = $this->realEscapeString($attendanceDetails->staffID);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $this->realEscapeString($attendanceDetails->hour);
        $subbatchId = $this->realEscapeString($attendanceDetails->subbatchId);
        $sbsId = $this->realEscapeString($attendanceDetails->sbsID);
        if (!empty($staffId)) {
            $sql_staff = " AND staffID = $staffId";
        }
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if ($subbatchId != NULL) {
            $sql_sub = " AND subbatchID=$subbatchId";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $sql = "delete from attendance_temporary where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sub $sql_sbs";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete from attendance_confirm
     * @param Attendance $attendanceDetails
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function deleteAttendanceConfirm($attendanceDetails)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $this->realEscapeString($attendanceDetails->hour);
        $subbatchId = $this->realEscapeString($attendanceDetails->subbatchId);
        $sbsId = $this->realEscapeString($attendanceDetails->sbsID);
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if ($subbatchId != NULL) {
            $sql_sub = " AND subbatchID=$subbatchId";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $sql = "delete from attendance_confirm where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_hour $sql_sub $sql_sbs";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete from attendance_confirm_temporary
     * @param Attendance $attendanceDetails
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function deleteAttendanceConfirmTemporary($attendanceDetails)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $this->realEscapeString($attendanceDetails->hour);
        $subbatchId = $this->realEscapeString($attendanceDetails->subbatchId);
        $sbsId = $this->realEscapeString($attendanceDetails->sbsID);
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if ($subbatchId != NULL) {
            $sql_sub = " AND subbatchID=$subbatchId";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $sql = "delete from attendance_confirm_temporary where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_hour $sql_sub $sql_sbs";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get Consolidated attendance details
     * @param string $attendanceDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getConsolidatedattendanceDetails($attendanceDate)
    {
        $attendanceDetails = [];
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $sql = "call getBatchwiseattendanceDetails('$attendanceDate')";
        try {
            $attendanceDetails = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_CONSOLIDATED_ATTENDANCE_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetails;
    }
    /**
     * get details of attendance temporary confirmed staff details
     * @param Attendance $attendance
     * @param boolean $sbsSpescific
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceTempConfirmedStaffDetails($attendance, $sbsSpescific = FALSE, $batchSpescific = FALSE)
    {
        $attendance = $this->realEscapeObject($attendance);
        $staffDetails = NULL;
        $sql = "SELECT distinct sa.staffID, act.subbatchID, act.sbsID, act.hour, act.attendanceDate, sa.staffName, IF(sa.staffID,IF(sbth.subbatchName !='',sbth.subbatchName,'All'),null) as subbatchName, sub.subjectName, act.batchID FROM attendance_confirm_temporary act INNER JOIN sbs_relation sr ON sr.sbsID=act.sbsID INNER JOIN staffaccounts sa ON sa.staffID=sr.staffID INNER JOIN subjects sub ON sub.subjectID=sr.subjectID LEFT JOIN subbatches sbth ON sbth.subbatchID=act.subbatchID WHERE act.batchID='" . $attendance->batchID . "' AND act.semID='" . $attendance->semID . "' AND act.hour='" . $attendance->hour . "' AND act.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "'";
        if ($attendance->subbatchId && !$batchSpescific) {
            $sql .= " AND act.subbatchID = '" . $attendance->subbatchId . "'";
        }
        if ($sbsSpescific) {
            $sql .= " AND act.sbsID = '$attendance->sbsID'";
        }
        try {
            $staffDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $staffDetails;
    }
    /**
     * get coninciding students
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentCoincidenceAttendanceTemp($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        if ($attendance->subbatchId) {
            $sql = 
            "SELECT DISTINCT 
                sa.studentID, sa.rollNo, sa.regNo, sa.admissionNo,sa.studentName,sa.batchID, atemp.sbsID, atemp.isAbsent, sa.myImage, sa.studentGender,st.staffName as confirmedStaff
            FROM attendance_temporary atemp
            INNER JOIN studentaccount sa ON sa.studentID = atemp.studentID AND atemp.batchID=sa.batchID
            INNER JOIN sbs_relation sbs ON sbs.sbsID = atemp.sbsID
            INNER JOIN staffaccounts st ON st.staffID = sbs.staffID 
            LEFT JOIN subbatch_student subb ON subb.studentID=atemp.studentID 
            WHERE atemp.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND atemp.batchID=$attendance->batchID AND atemp.semID=$attendance->semID AND atemp.hour=$attendance->hour and subb.subbatchID = '$attendance->subbatchId";
        } else {
            $sql = 
            "SELECT DISTINCT 
                sa.studentID, sa.rollNo, sa.regNo, sa.admissionNo,sa.studentName,sa.batchID, atemp.sbsID, atemp.isAbsent,st.staffName as confirmedStaff
            FROM attendance_temporary atemp
            INNER JOIN studentaccount sa ON sa.studentID = atemp.studentID AND atemp.batchID=sa.batchID 
            INNER JOIN sbs_relation sbs ON sbs.sbsID = atemp.sbsID
            INNER JOIN staffaccounts st ON st.staffID = sbs.staffID 
            WHERE atemp.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND atemp.batchID=$attendance->batchID AND atemp.semID=$attendance->semID AND atemp.hour=$attendance->hour ";
        }
        try {
            $sql .= "ORDER BY sa.$attendance->sortBy";
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * get coninciding students
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentCoincidenceAttendance($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        if ($attendance->subbatchId) {
            $sql = "SELECT DISTINCT sa.studentID, sa.rollNo, sa.regNo, sa.admissionNo,
                sa.studentName,
                sa.batchID,
                att.isAbsent,
                sta.staffName as confirmedStaff,
                sub.subjectDesc,
                sa.myImage,
                sa.studentGender
           FROM attendance att
     INNER JOIN studentaccount sa ON sa.studentID = att.studentID AND att.batchID=sa.batchID INNER JOIN attendance_confirm ac ON ac.batchID=att.batchID AND ac.semID=att.semID AND att.sbsID=ac.sbsID AND ac.attendanceDate=att.attendanceDate AND att.hour=ac.hour INNER JOIN sbs_relation sb ON sb.sbsID=att.sbsID INNER JOIN staffaccounts sta ON sta.staffID=sb.staffID INNER JOIN subjects sub ON sub.subjectID=sb.subjectID INNER JOIN subbatch_student ss ON ss.studentID=sa.studentID AND ss.subbatchID=$attendance->subbatchId WHERE att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND att.batchID=$attendance->batchID AND att.semID=$attendance->semID AND att.hour=$attendance->hour ORDER BY sa.$attendance->sortBy";
        } else {
            $sql = "SELECT DISTINCT sa.studentID, sa.rollNo, sa.regNo, sa.admissionNo,
                sa.studentName,
                sa.batchID,
                att.isAbsent,
                sta.staffName as confirmedStaff,
                sub.subjectDesc
           FROM attendance att
     INNER JOIN studentaccount sa ON sa.studentID = att.studentID AND att.batchID=sa.batchID INNER JOIN attendance_confirm ac ON ac.batchID=att.batchID AND ac.semID=att.semID AND att.sbsID=ac.sbsID AND ac.attendanceDate=att.attendanceDate AND att.hour=ac.hour INNER JOIN sbs_relation sb ON sb.sbsID=att.sbsID INNER JOIN staffaccounts sta ON sta.staffID=sb.staffID INNER JOIN subjects sub ON sub.subjectID=sb.subjectID WHERE att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND att.batchID=$attendance->batchID AND att.semID=$attendance->semID AND att.hour=$attendance->hour ORDER BY sa.$attendance->sortBy";
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * add attendance confirm temporary
     * @param Attendance $attendance
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function addAttendanceConfirmTemp($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $sql = "INSERT INTO attendance_confirm_temporary(batchID, subbatchID, semID, hour, attendanceDate, sbsID) VALUES('" . $attendance->batchID . "', '" . $attendance->subbatchId . "', '" . $attendance->semID . "', '" . $attendance->hour . "', '" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "', '" . $attendance->sbsID . "')";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get unmarked student from batch or subbatch
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getUnmarkedStudents($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($attendance->batchID, $attendance->semID);
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($attendance->semID);
        if ($attendance->subbatchId) {
            if ($isCurrentSem) {
                $sql = "select sta.studentID, sta.studentName, sta.rollNo, sta.regNo, sta.admissionNo, at.isAbsent, at.sbsID as markedSbsId, if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sta.myImage, sta.studentGender from studentaccount sta INNER JOIN  subbatches subb ON subb.batchID=sta.batchID INNER JOIN  subbatch_student substu ON sta.studentID=substu.studentID AND substu.subbatchID=subb.subbatchID LEFT JOIN attendance at ON at.studentID=sta.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID inner join semesters joinSem on joinSem.semID = sta.joiningSemId inner join batches ba on ba.batchID = sta.batchID inner join semesters sem on sem.semID = ba.semID  where subb.semID=$attendance->semID AND substu.subbatchID=$attendance->subbatchId and joinSem.orderNo <= sem.orderNo AND sta.studentID NOT IN(select t1.studentID from studentaccount t1, subbatch_student t2, attendance_temporary t3 where t2.subbatchID=\"" . $attendance->subbatchId . "\" and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=\"" . $attendance->hour . "\" and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=\"" . $attendance->batchID . "\" and t3.semID=\"" . $attendance->semID . "\")";
            } else {
                $sql = "select sta.studentID, sta.studentName, sta.rollNo, sta.regNo, sta.admissionNo, at.isAbsent, at.sbsID as markedSbsId, if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sta.myImage, sta.studentGender from studentaccount sta INNER JOIN  subbatches subb ON subb.batchID=sta.batchID INNER JOIN subbatch_student substu ON sta.studentID=substu.studentID AND substu.subbatchID=subb.subbatchID LEFT JOIN attendance at ON at.studentID=sta.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID where subb.semID=$attendance->semID AND substu.subbatchID=$attendance->subbatchId AND sta.studentID NOT IN(select t1.studentID from studentaccount t1, subbatch_student t2, attendance_temporary t3 where t2.subbatchID=\"" . $attendance->subbatchId . "\" and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=\"" . $attendance->hour . "\" and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=\"" . $attendance->batchID . "\" and t3.semID=\"" . $attendance->semID . "\") AND sta.studentID in(select sa.studentID from studentaccount sa  inner join semesters joinSem on joinSem.semID = sa.joiningSemId inner join batches ba on ba.batchID = sa.batchID inner join semesters sem on sem.semID = ba.semID where ba.batchID = $attendance->batchID and joinSem.orderNo <= sem.orderNo union select sa.studentID from failed_students fs inner join studentaccount sa on sa.studentID = fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo)";
            }
        } else {
            if ($isCurrentSem) {
                $sql = "select sa.studentID, sa.studentName, sa.rollNo, sa.regNo, sa.admissionNo, at.isAbsent, at.sbsID as markedSbsId,  if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sa.myImage, sa.studentGender from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on joinedSem.semID = sa.joiningSemId LEFT JOIN attendance at ON at.studentID=sa.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID where sa.batchID=$attendance->batchID and joinedSem.orderNo <= sem.orderNo AND sa.studentID NOT IN(select t1.studentID from  studentaccount t1, attendance_temporary t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID)";
            } else {
                $sql = "select studentID, studentName, rollNo, regNo, admissionNo, myImage, studentGender from (select studentID, studentName, rollNo, regNo, admissionNo, sa.myImage, sa.studentGender from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on joinedSem.semID = sa.joiningSemId  where ba.batchID = $attendance->batchID and joinedSem.orderNo <= $semDetails->orderNo union select fs.studentID, studentName, rollNo, regNo, admissionNo, sa.myImage, sa.studentGender from failed_students fs inner join studentaccount sa on sa.studentID = fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from  studentaccount t1, attendance_temporary t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID);";
            }
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * add students to attendance temporary
     * @param Attendance array $attendanceList
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function addAttendanceTemp($attendanceList)
    {
        $attendanceList = $this->realEscapeArray($attendanceList);
        $attendance = array_pop(array_merge(array(), $attendanceList));
        $batchTimetable = new BatchTimetable();
        $batchTimetable->batchId =$attendance->batchID;
        $batchTimetable->subbatchId = $attendance->subbatchId;
        $batchTimetable->semId = $attendance->semID;
        $batchTimetable->timetableDate = date('Y-m-d', strtotime($attendance->attendanceDate));
        $batchTimetable->hourId= $attendance->hour;
        $batchTimetable->sbsId=$attendance->sbsID;
        $hourDetails = TimetableService::getInstance()->getHourDetails($batchTimetable);
        $meetingAttendedStudentList=[];
        if($hourDetails->oicMeetingId)
        {
            $meetingAttendedStudentList = OnlineInteractiveClassService::getInstance()->getMeetingAttendedStudents($hourDetails->oicMeetingId);
            if(!empty($meetingAttendedStudentList))
            {
                $meetingStudentIdList = array_map(function ($obj) {
                    return $obj->student_id;
                }, $meetingAttendedStudentList);
                    
            }
        }
        $value = [];
        foreach ($attendanceList as $attendance) {
            if(!empty($meetingStudentIdList))
            {
                if(in_array($attendance->studentID, $meetingStudentIdList))
                {
                    $attendance->isAbsent=0;
                }
                else
                {
                    $attendance->isAbsent=1;
                }
            }
            $value[] = "('" . $attendance->studentID . "', '" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "', '" . $attendance->hour . "', '" . $attendance->semID . "', '" . $attendance->batchID . "', '" . $attendance->sbsID . "', '" . $attendance->staffID . "', '$attendance->subbatchId', '$attendance->isAbsent')";
        }
        $sql = "INSERT INTO attendance_temporary (studentID, attendanceDate, hour, semID, batchID, sbsID, staffID, subbatchID, isAbsent) VALUES " . implode(',', $value);
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get drafted students from attendance temporary
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentsFromAttendanceTemp($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        if ($attendance->subbatchId) {
            $sql = "SELECT t1.studentID,
                             t1.studentName,
                             t1.rollNo,
                             t1.regNo,
                             t1.admissionNo,
                             t3.isAbsent,
                             t1.myImage,
                             t1.studentGender 
                             FROM 
                             studentaccount t1,
                             subbatch_student t2,
                             attendance_temporary t3 
                             WHERE t2.subbatchID='" . $attendance->subbatchId . "
                             AND t1.studentID=t2.studentID 
                             AND t2.studentID=t3.studentID 
                             AND t3.hour=$attendance->hour 
                             AND t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' 
                             AND t3.batchID='" . $attendance->batchID . "
                             AND t3.semID=$attendance->semID 
                             ORDER BY t1.$attendance->sortBy";
        } else {
            $sql = "SELECT t1.studentID,
                            t1.studentName,
                            t1.rollNo,
                            t1.regNo,
                            t1.admissionNo,
                            t3.isAbsent,
                            t1.myImage,
                            t1.studentGender 
                            FROM  
                            studentaccount t1,
                            attendance_temporary t3  
                            WHERE t1.studentID=t3.studentID 
                            AND t3.batchID=$attendance->batchID 
                            AND t3.hour=$attendance->hour 
                            AND t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "
                            AND t3.semID=$attendance->semID 
                            ORDER BY t1.rollNo";
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
                $sqlCheck = "SELECT id,date,hours from attendance_blocked_students WHERE studentId = $student->studentID and date = '$attendance->attendanceDate' AND FIND_IN_SET('$attendance->hour', hours) > 0;";
                $studentDetails[$idx]->Block = $this->executeQueryForObject($sqlCheck) ? true : false;
                
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * get students from attendance
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentsFromAttendance($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        if ($attendance->subbatchId) {
            $sql = "select sa.studentID, sa.studentName, sa.rollNo, sa.regNo, sa.admissionNo, att.isAbsent, ";
            if ($attendance->subjectID) {
                $sql .= "CASE WHEN sr.subjectID=$attendance->subjectId AND sr.batchID=sa.batchID THEN null ELSE true END as conflict, ";
            } else {
                $sql .= "IF(att.sbsID=$attendance->sbsID,null,true) as conflict, ";
            }
            $sql .= "att.sbsID, att.hour from attendance att INNER JOIN studentaccount sa ON sa.studentID=att.studentID INNER JOIN batches bt ON bt.batchID=sa.batchID INNER JOIN sbs_relation sr ON sr.sbsID=att.sbsID INNER JOIN subbatch_student ss ON ss.studentID=sa.studentID WHERE sa.batchID=$attendance->batchID AND att.hour=$attendance->hour AND att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND att.semID=$attendance->semID AND ss.subbatchID=$attendance->subbatchId ORDER BY sa.$attendance->sortBy";
        } else {
            $sql = "select sa.studentID, sa.studentName, sa.rollNo, sa.regNo, sa.admissionNo, att.isAbsent, ";
            if ($attendance->subjectID) {
                $sql .= "CASE WHEN sr.subjectID=$attendance->subjectId AND sr.batchID=sa.batchID THEN null ELSE true END as conflict, ";
            } else {
                $sql .= "IF(att.sbsID=$attendance->sbsID,null,true) as conflict, ";
            }
            $sql .= "att.sbsID, att.hour from attendance att INNER JOIN studentaccount sa ON sa.studentID=att.studentID INNER JOIN batches bt ON bt.batchID=sa.batchID INNER JOIN sbs_relation sr ON sr.sbsID=att.sbsID WHERE sa.batchID=$attendance->batchID AND att.hour=$attendance->hour AND att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND att.semID=$attendance->semID ORDER BY sa.$attendance->sortBy";
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
                $sqlCheck = "SELECT id,date,hours from attendance_blocked_students WHERE studentId = $student->studentID and date = '$attendance->attendanceDate' AND FIND_IN_SET('$attendance->hour', hours) > 0";
                $studentDetails[$idx]->isBlocked = $this->executeQueryForObject($sqlCheck) ? true : false;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * update attendance confirm temporary
     * @param Attendance $attendance
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function updateAttendanceConfirmTemp($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $sql = "UPDATE attendance_confirm_temporary SET sbsID='" . $attendance->sbsID . "' WHERE batchID='" . $attendance->batchID . "' AND subbatchID='" . $attendance->subbatchId . "' AND semID='" . $attendance->semID . "' AND hour='" . $attendance->hour . "' AND attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "'";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get batch all confirmed staffDetails
     * @param int $batchId
     * @param int $semId
     * @param int $hour
     * @param string $attendanceDate
     * @param int $sbsId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceConfirmedForAllbatchStaffDetails($batchId, $semId, $hour, $attendanceDate, $sbsId = null)
    {
        $staffDetails = NULL;
        $sql = "SELECT sa.staffID, ac.subbatchID, if(sb.subbatchName !='',sb.subbatchName,'All') as subbatchName
, sr.sbsID, sa.staffName, ac.confirmedDate, ac.exam_id as examId, subj.subjectDesc, subj.subjectName FROM attendance_confirm ac INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID INNER JOIN subjects subj ON subj.subjectID=sr.subjectID INNER JOIN staffaccounts sa ON sa.staffID=sr.staffID LEFT JOIN subbatches sb ON sb.subbatchID=ac.subbatchID WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.hour='$hour' AND ac.attendanceDate='" . date('Y-m-d', strtotime($attendanceDate)) . "' AND ac.subbatchID = 0";
        if ($sbsId) {
            $sql .= " AND ac.sbsID = '" . $sbsId . "'";
        }
        try {
            $staffDetails = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $staffDetails;
    }
    /**
     * get unmarked student from batch or subbatch
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getUnmarkedStudentAfterConfirm($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($attendance->semID);
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($attendance->batchID, $attendance->semID);
        if ($attendance->subbatchId) {
            if ($isCurrentSem) {
                $sql = "select sta.studentID from studentaccount sta inner join  subbatch_student substu on sta.studentID=substu.studentID inner join semesters joinSem on joinSem.semID = sta.joiningSemId inner join batches ba on ba.batchID = sta.batchID inner join semesters sem on sem.semID = ba.semID  where  substu.subbatchID=$attendance->subbatchId AND joinSem.orderNo <= sem.orderNo AND sta.studentID NOT IN(select t1.studentID from studentaccount t1, subbatch_student t2, attendance t3 where t2.subbatchID=\"" . $attendance->subbatchId . "\" and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=\"" . $attendance->hour . "\" and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=\"" . $attendance->batchID . "\" and t3.semID=\"" . $attendance->semID . "\")";
            } else {
                $sql = "select studentID from (select sta.studentID from studentaccount sta inner join subbatch_student substu on sta.studentID=substu.studentID inner join semesters joinSem on joinSem.semID = sta.joiningSemId where substu.subbatchID=$attendance->subbatchId AND sta.batchID='$attendance->batchID' and joinSem.orderNo <= $semDetails->orderNo union select fs.studentID from failed_students fs inner join subbatch_student sub on fs.studentID=sub.studentID inner join studentaccount sa ON sa.studentID=sub.studentID inner join semesters fSem on fSem.semID = fs.failedInSemester  where sub.subbatchID=$attendance->subbatchId AND fs.previousBatch = $attendance->batchID and fSem.orderNo > $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from studentaccount t1, subbatch_student t2, attendance t3 where t2.subbatchID=$attendance->subbatchId and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=$attendance->batchID and t3.semID=$attendance->semID)";
            }
        } else {
            if ($isCurrentSem) {
                $sql = "select studentID from studentaccount sa inner join batches ba on sa.batchID =  ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where ba.batchID=$attendance->batchID AND joinedSem.orderNo <= sem.orderNo AND studentID NOT IN(select t1.studentID from  studentaccount t1, attendance t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID)";
            } else {
                $sql = "select studentID from (select studentID from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where sa.batchID=$attendance->batchID AND joinedSem.orderNo <= $semDetails->orderNo union select fs.studentID from failed_students fs inner join studentaccount sa ON sa.studentID=fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from  studentaccount t1, attendance t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID)";
            }
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * Calculating attendance taken hours for this particular faculty.
     * @param Timetable $timetable
     * @return int
     * @throws ProfessionalException
     */
    public function getAttendanceTakenHours($timetable)
    {
        $attendedHours = 0;
        $subbatchDetails = BatchService::getInstance()->getSubbatchDetailsBySbsId($timetable);
        $deptId = BatchService::getInstance()->getBatchDetailsById($timetable->batchID)->deptId;
        $subCond = " AND t1.subbatchID =0";
        if (!empty($subbatchDetails) && $subbatchDetails != NULL) {
            $subbatchID = array_map(function ($obj) {
                return $obj->subbatchID;
            }, $subbatchDetails);
            $subCond = " AND t1.subbatchID IN(" . implode(',', $subbatchID) . ",0)";
        }
        $holidays = CalendarService::getInstance()->getHolidays($deptId, $timetable->batchID, $timetable->timetableDate);
        $sql = "SELECT distinct t1.attendanceDate, t1.hour FROM attendance_confirm t1, batch_timetable t2 WHERE t1.batchID = t2.batchID AND t1.hour = t2.hourID AND t1.attendanceDate = t2.timetableDate AND t1.batchID = " . $timetable->batchID . " AND t1.semID=" . $timetable->semID . " AND t2.sbsID=" . $timetable->sbsID . " AND t1.attendanceDate <= \"" . $timetable->timetableDate . "\" AND timetableDate NOT IN ('" . implode("','", $holidays) . "') $subCond group by t1.hour, t1.attendanceDate";
        try {
            $attendedHours = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return count($attendedHours);
    }
    /**
     * Calculating attendance taken hours for this particular faculty.
     * @param Timetable $timetable
     * @return int
     * @throws ProfessionalException
     */
    public function getAssignedAttendanceTakenHours($timetable)
    {
        $attendedHours = 0;
        $subbatchDetails = BatchService::getInstance()->getSubbatchDetailsBySbsId($timetable);
        $deptId = BatchService::getInstance()->getBatchDetailsById($timetable->batchID)->deptId;
        $subCond = " AND t1.subbatchID =0";
        if (!empty($subbatchDetails) && $subbatchDetails != NULL) {
            $subbatchID = array_map(function ($obj) {
                return $obj->subbatchID;
            }, $subbatchDetails);
            $subCond = " AND t1.subbatchID IN(" . implode(',', $subbatchID) . ",0)";
        }
        $holidays = CalendarService::getInstance()->getHolidays($deptId, $timetable->batchID, $timetable->timetableDate);
        $sql = "SELECT distinct distinct t1.attendanceDate, t1.hour FROM attendance_confirm t1, batch_timetable t2 WHERE t1.batchID = t2.batchID AND t1.hour = t2.hourID AND t1.attendanceDate = t2.timetableDate AND t1.sbsID=t2.sbsID AND t1.batchID = " . $timetable->batchID . " AND t1.semID=" . $timetable->semID . " AND t2.sbsID=" . $timetable->sbsID . " AND t1.attendanceDate <= \"" . $timetable->timetableDate . "\" AND timetableDate  NOT IN ('" . implode("','", $holidays) . "') $subCond group by t1.hour, t1.attendanceDate";
        try {
            $attendedHours = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return count($attendedHours);
    }
    /**
     * Calculating unlocked attendance taken hours for this particular faculty.
     * @param Timetable $timetable
     * @return int
     * @throws ProfessionalException
     */
    public function getTotalAttendanceTakenHours($timetable)
    {
        $attendedHours = 0;
        $subbatchDetails = BatchService::getInstance()->getSubbatchDetailsBySbsId($timetable);
        $deptId = BatchService::getInstance()->getBatchDetailsById($timetable->batchID)->deptId;
        $subCond = " AND t1.subbatchID =0";
        if (!empty($subbatchDetails) && $subbatchDetails != NULL) {
            $subbatchID = array_map(function ($obj) {
                return $obj->subbatchID;
            }, $subbatchDetails);
            $subCond = " AND t1.subbatchID IN(" . implode(',', $subbatchID) . ",0)";
        }
        $holidays = CalendarService::getInstance()->getHolidays($deptId, $timetable->batchID, $timetable->timetableDate);
        $sql = "SELECT distinct distinct t1.attendanceDate, t1.hour FROM attendance_confirm t1, batch_timetable t2 WHERE t1.batchID = t2.batchID AND t1.hour = t2.hourID AND t1.attendanceDate = t2.timetableDate AND t1.batchID = " . $timetable->batchID . " AND t1.semID=" . $timetable->semID . " AND t1.sbsID=" . $timetable->sbsID . " AND t1.attendanceDate <= \"" . $timetable->timetableDate . "\" AND timetableDate  NOT IN ('" . implode("','", $holidays) . "') $subCond group by t1.hour, t1.attendanceDate";
        try {
            $attendedHours = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return count($attendedHours);
    }
    /**
     * Calculating suspended hours for this particular faculty.
     * @param Timetable $timetable
     * @return int
     * @throws ProfessionalException
     */
    public function getSuspendedHourCount($timetable)
    {
        $suspendCount = 0;
        $deptId = BatchService::getInstance()->getBatchDetailsById($timetable->batchID)->deptId;
        $holidays = CalendarService::getInstance()->getHolidays($deptId, $timetable->batchID, $timetable->timetableDate);
        $sql = "select count(suspended) as suspendCount FROM (SELECT count(t1.timetableID) as suspended FROM batch_timetable t1, suspended_hours t2 WHERE t1.batchID=\"" . $timetable->batchID . "\" AND t1.semID=\"" . $timetable->semID . "\" AND t1.sbsID=\"" . $timetable->sbsID . "\" AND t1.timetableDate <= \"" . $timetable->timetableDate . "\" AND t1.timetableDate=t2.suspendedDate AND t1.hourID=t2.hour AND t1.batchID=t2.batchID AND t1.semID=t2.semID AND t1.timetableDate NOT IN ('" . implode("','", $holidays) . "') group by t1.timetableDate, t1.hourID) as suspendedDetails";
        try {
            $suspendCount = $this->executeQueryForObject($sql)->suspendCount;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $suspendCount;
    }
    /**
     * Method for checking attendance modify options for the given role and action
     *
     * @param string $role
     * @param string $menuAction
     * @return boolean
     * @throws ProfessionalException
     */
    public function hasAttendanceModifyPrivillege($role, $menuAction)
    {
        $hasPrivillege = false;
        if (!empty($role) && !empty($menuAction)) {
            $sql = "SELECT disabled FROM edit_attendance_option_privilege WHERE menu_action='$menuAction' AND role = '$role'";
            try {
                $responseObj = $this->executeQueryForObject($sql);
                if (empty($responseObj)) {
                    $hasPrivillege = true;
                } else {
                    $hasPrivillege = !$responseObj->disabled;
                }
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
        }
        return $hasPrivillege;
    }
    /**
     * To get pseudosubject attendance details
     * @param string $sbsIds
     * @param string $fromDay
     * @param string $toDay
     * @param int $psID
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getPseudoSubjectAttendanceDetails($sbsIds, $fromDay, $toDay, $pseudosubjectId, $sortBy = "studentID")
    {
        $sbsIds = $this->realEscapeString($sbsIds);
        $fromDay = $this->realEscapeString($fromDay);
        $toDay = $this->realEscapeString($toDay);
        $sortBy = $this->realEscapeString($sortBy);
        $pseudosubjectId = $this->realEscapeString($pseudosubjectId);
        $sql = "SELECT
                sa.rollNo,
                sa.regNo,
                sa.studentID,
                sa.studentName,
                b.batchID,
                b.batchName,
                subb.subbatchName,
                sub.subjectID,
                sub.subjectName,
                sta.staffID,
                sta.staffName,
                dep.deptID,
                dep.deptName,
                concat(sa.studentID,att.hour,att.attendanceDate,att.semID) as attendanceId,
                att.attendanceDate,
                att.hour,
                if(att.isAbsent =0,'P', 'A') as isAbsent
            FROM
               pseudosubjects_students ps
                    left JOIN
                studentaccount sa ON ps.studentID = sa.studentID 
                    LEFT JOIN 
                batches b ON b.batchID = sa.batchID
                    left JOIN
                subbatches subb ON subb.psID = ps.pseudosubjectID
                    left JOIN
                attendance att ON att.studentID = sa.studentID
                    AND att.studentID = ps.studentID
                    AND att.batchID = subb.batchID
                    INNER JOIN
                department dep ON dep.deptID = sa.deptID
                    left JOIN
                sbs_relation sbs ON att.sbsID = sbs.sbsID
                    left JOIN
            subjects sub on sbs.subjectID = sub.subjectID left JOIN
        staffaccounts sta ON sta.staffID = sbs.staffID
            WHERE
                att.sbsID IN ($sbsIds)  and pseudosubjectID = $pseudosubjectId
                    AND attendanceDate BETWEEN '$fromDay' AND '$toDay'
ORDER BY sa.$sortBy,attendanceDate,hour";
        try {
            $attendanceDetails = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_PSEUDOSUBJECT_ATTENDANCE_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetails;
    }
    /**
     * To get marked attendance dates by pseudosubjectId
     * @param int $pseudoSubjectId
     * @param string $fromDay
     * @param string $toDay
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getPseudoSubjectAttendanceMarkedDates($pseudoSubjectId, $fromDay, $toDay)
    {
        $fromDay = $this->realEscapeString($fromDay);
        $toDay = $this->realEscapeString($toDay);
        $pseudoSubjectId = $this->realEscapeString($pseudoSubjectId);
        $sql = "SELECT DISTINCT attendanceDate,hour FROM attendance_confirm ac INNER JOIN subbatches subb ON subb.subbatchID = ac.subbatchID LEFT JOIN pseudosubjects_sbs psbs ON ac.sbsID = psbs.sbsID AND subb.psID = psbs.pseudosubjectID WHERE psbs.pseudosubjectID = $pseudoSubjectId  AND attendanceDate BETWEEN '$fromDay' AND '$toDay' ORDER BY attendanceDate, hour";
        try {
            $attendanceDates = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDates;
    }
    /**
     * To get absentee list perday by sbsId
     * @param string $sbsId
     * @param string $date
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAbsenteesListPerDayBySbsIds($sbsId, $date)
    {
        $sbsId = $this->realEscapeString($sbsId);
        $date = $this->realEscapeString($date);
        $sql = "select sa.studentID, sa.rollNo, sa.studentName, dep.deptId, dep.deptName, bat.batchId, bat.batchName, group_concat(hour order by hour) as hours from studentaccount sa left join attendance att on sa.studentID = att.studentID inner join batches bat on sa.batchID = bat.batchID inner join department dep on dep.deptID = bat.deptID where sbsID in ($sbsId) and attendanceDate = '$date' and isAbsent = 1 group by studentID  order by  bat.batchID, sa.rollNo, hour";
        try {
            $absenteeList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $absenteeList;
    }
    /** Get student attendance details subject wise
     * @param int $batchId
     * @param int $semId
     * @param int $studentId
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    function getStudentAttendanceDetailsSubjectWise($batchId, $semId, $studentId, $fromDate, $toDate, $attendanceRules = null)
    {
        if($attendanceRules->dateOfjoining)
        {
            $studentJoiningDate = StudentService::getInstance()->getStudentDetailsById($studentId)->studentJoindate;
            if($studentJoiningDate)
            {
                if( $attendanceRules->dateOfjoining && (strtotime($studentJoiningDate) >  strtotime($fromDate)))
                {
                    $hisfromDate = $studentJoiningDate;
                }
                else
                {
                    $hisfromDate = $fromDate;
                }
            }
        }
        $fromDate = $hisfromDate ? $hisfromDate : $fromDate;
        $sql = "SELECT sub.subjectID,
                         sub.subjectName,
                         sub.subjectDesc,
                         sub.subjectcatID,
                        (COUNT(CASE WHEN  (att.isAbsent=0 OR att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END)/COUNT(att.studentID)) * 100 AS attPercent,
                        (COUNT(CASE WHEN (att.isAbsent=0 OR att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END))AS atthour,
                        (COUNT(CASE WHEN (att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END))AS dlCount,
                         COUNT(att.studentID) as totalhour
                          FROM attendance att 
                          inner join sbs_relation sbs on  att.sbsID = sbs.sbsID AND att.batchID=sbs.batchID AND att.semID=sbs.semID 
                          left join subjects sub on sbs.subjectID = sub.subjectID 
                          WHERE att.studentID = $studentId AND att.semID= $semId and att.batchID = $batchId and attendanceDate between '$fromDate' and '$toDate
                          group by sub.subjectID";
        $attendanceDetails = $this->executeQueryForList($sql);
        try {
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetails;
    }
     /** Get student attendance details subject wise
     * @param int $batchId
     * @param int $semId
     * @param int $studentId
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    function getStudentAttendanceDetailsSubjectWiseForCondonation($batchId, $semId, $studentId, $fromDate, $toDate)
    {
        $sql = "SELECT sub.subjectID,
                         sub.subjectName,
                         sub.subjectDesc,
                         sub.subjectcatID,
                         s.staffID,
                         s.staffName,
                        (COUNT(CASE WHEN  (att.isAbsent=0 OR att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END)/COUNT(att.studentID)) * 100 AS attPercent,(COUNT(CASE WHEN (att.isAbsent=0 OR att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END))AS atthour,
                        (COUNT(CASE WHEN (att.isAbsent=2) AND att.isBlocked = 0 THEN 1 END))AS dlCount, COUNT(att.studentID) as totalhour FROM attendance att inner join sbs_relation sbs on  att.sbsID = sbs.sbsID AND att.batchID=sbs.batchID AND att.semID=sbs.semID 
                        left join subjects sub on sbs.subjectID = sub.subjectID 
                        inner join staffaccounts s on s.staffID = sbs.staffID 
                        WHERE att.studentID = $studentId 
                        AND att.semID= $semId 
                        and att.batchID = $batchId 
                        and attendanceDate 
                        between '$fromDate' and '$toDate' group by sub.subjectID";
try {
        $attendanceDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetails;
    }
    function getStudentAttendanceDetailsForASubject($batchId, $semId, $subjectId, $fromDate = null, $toDate = null)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "SELECT s.studentId, s.studentName, s.studentJoindate,(CASE WHEN s.totalhour=0 THEN NULL else s.attPercent END) as attPercent ,s.atthour, s.totalhour from (
            SELECT sta.studentID as studentId, sta.studentName, sta.studentJoindate , (COUNT(CASE WHEN  att.isAbsent=0 OR att.isAbsent=2 THEN 1 END)/COUNT(att.studentID)) * 100 AS attPercent,(COUNT(CASE WHEN att.isAbsent=0 OR att.isAbsent=2 THEN 1 END))AS atthour,COUNT(att.studentID) as totalhour FROM studentaccount sta INNER JOIN attendance att ON att.studentID = sta.studentID inner join sbs_relation sbs on  att.sbsID = sbs.sbsID left join subjects sub on sbs.subjectID = sub.subjectID WHERE att.semID= $semId and att.batchID = $batchId  AND sub.subjectID = $subjectId ";
        if (!empty($fromDate) && !empty($toDate)) {
            $sql .= " AND attendanceDate between '$fromDate' and '$toDate'";
        } else {
            try {
                $attendanceRules = AttendanceService::getInstance()->getAttendanceRule($batchId, $semId);
            } catch (\Exception $e) {
                $attendanceRules = [];
            }
            $fromDate = null;
            $toDate = null;
            if (!empty($attendanceRules)) {
                if ($attendanceRules->dateOfjoining) {
                    $fromDate = "sta.studentJoindate";
                } else {
                    $fromDate = "'" . $attendanceRules->classStartsFrom . "'";
                }
                $toDate = $attendanceRules->classEnds;
                if ($toDate != "0000-00-00" && $toDate)
                    $sql .= " AND attendanceDate between $fromDate and '$toDate'";
                else
                    $sql .= " AND attendanceDate > $fromDate";
            }
        }
        $sql .= " group by sta.studentID) s;";
        try {
            $attendanceDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetails;
    }
    /**
     *
     * @param GetAbsentHoursOfAStudentByDateRequest $request
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     * @author gadheyan
     */
    public function getAbsentHoursOfAStudentByDate(GetAbsentHoursOfAStudentByDateRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "";
        $sql = "select hour from attendance WHERE semID = '$request->semId' AND batchID = '$request->batchId' AND attendanceDate = '$request->attendanceDate' AND isAbsent = 1 AND studentID = '$request->studentId';";
        try {
            $result = [];
            $result = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        $response = [];
        foreach ($result as $item) {
            $response[] = $item->hour;
        }
        return $response;
    }
    /**
     * To get pseudo subject attendance marked date
     * @param string $attendanceDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceMarkedPseudoSubjectsByDate($attendanceDate)
    {
        $sql = "select distinct sub.subjectID, sub.subjectName from attendance_confirm ac inner join pseudosubjects_sbs psbs on psbs.sbsID = ac.sbsID inner join  sbs_relation sr on ac.sbsID = sr.sbsID inner join subjects sub on sub.subjectID = sr.subjectID where attendanceDate = '$attendanceDate'";
        try {
            $subjects = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $subjects;
    }
    /**
     * To get absentees count for pseudo subject by date
     * @param string $attendanceDate
     * @param array $subjectIds
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getPseudoSubjectAbsenteesCountByDate($attendanceDate, $subjectIds = null)
    {
        $attendanceDate = $this->realEscapeString($attendanceDate);
        if ($subjectIds) {
            $subjectIds = implode(",", $subjectIds);
            $sql_subjectId = " and sub.subjectID in ($subjectIds)";
        }
        $sql = "SELECT
                sub.subjectID, sub.subjectName, bat.batchID, bat.batchName, bat.semID, dep.deptID as deptId, dep.deptName, sr.sbsID, hour , count(studentID) as strength,
                count(case when isAbsent =  1 then 1  end ) as absenteesNo
            FROM
            pseudosubjects_sbs psbs
                    LEFT JOIN
                sbs_relation sr ON psbs.sbsID = sr.sbsID
                    LEFT JOIN
                subjects sub ON sr.subjectID = sub.subjectID
                    LEFT JOIN
                batches bat ON sr.batchID = bat.batchID
                    AND sr.semID = bat.semID
                    LEFT JOIN
                    department dep ON bat.deptID = dep.deptID
                    LEFT JOIN
                attendance att ON att.sbsID = sr.sbsID where  attendanceDate = '$attendanceDate$sql_subjectId
            GROUP BY  sub.subjectID, bat.batchID, hour
            ORDER BY sub.subjectID,dep.deptID, bat.batchID , attendanceDate , hour";
        try {
            $absenteesList = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_PSEUDOSUBJECT_ABSENTEES_COUNT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $absenteesList;
    }
    /**
     * Get student attendance percentage hour wise by studentId
     * @param int $studentId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentAttendancePercentageHourWise($studentId)
    {
        $studentId = $this->realEscapeString($studentId);
        $sql = "select (count(case when isAbsent = 0 then 1 end )/ count(sa.studentID)) * 100 as attendancePercent from attendance att inner join studentaccount sa on att.studentID = sa.studentID and sa.batchID = att.batchId inner join batches bat on bat.batchID = sa.batchID and att.semID = bat.semID where sa.studentID = $studentId";
        try {
            $attendancePercent = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendancePercent;
    }
    /**
     * Get student expected attendance percentage hour wise by studentId
     * @param int $studentId
     * @param int $totalWorkingHours
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentExpectedAttendancePercentageHourWise($studentId, $totalWorkingHours)
    {
        $studentId = $this->realEscapeString($studentId);
        $totalWorkingHours = $this->realEscapeString($totalWorkingHours);
        $sql = "select ((present + hoursToTakeAttn)/$totalWorkingHours) * 100 as expectedMaxAttendancePercent from (select (count(case when isAbsent = 0 then 1 end )) as present , ($totalWorkingHours - count(sa.studentID)) as hoursToTakeAttn from attendance att inner join studentaccount sa on att.studentID = sa.studentID and sa.batchID = att.batchId inner join batches bat on bat.batchID = sa.batchID and att.semID = bat.semID where sa.studentID = $studentId) as expectedPercentage";
        try {
            $attendancePercentage = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendancePercentage;
    }
    /**
     * Get no of attendance marked date by batchID and semID
     * @param int $batchId
     * @param int $semID
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getNoOfHoursByBatch($date, $batchId, $semId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $hours = NULL;
        $sql = "select COUNT(DISTINCT(attendanceDate)) as hours from attendance_confirm  where batchID = $batchId AND semID = $semId AND attendanceDate<='$date'";
        try {
            $hours = $this->executeQueryForObject($sql)->hours;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $hours;
    }
    /**
     * Get no of attendance marked date by batchID and semID
     * @param int $batchId
     * @param int $semID
     * @param int $studentId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getNoOfHoursAttendedByStudentId($date, $batchId, $semId, $studentId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $hours = NULL;
        $sql = "select COUNT(DISTINCT(attendanceDate)) as hours from attendance  where batchID = $batchId AND semID = $semId AND studentID=$studentId AND isAbsent=0 AND attendanceDate<='$date'";
        try {
            $hours = $this->executeQueryForObject($sql)->hours;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $hours;
    }
    /**
     * Get student attendance details for a date range
     * @param int $batchId
     * @param int $semId
     * @param string $fromDate
     * @param string $toDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentAttDetailsInDateRange($batchId, $semId, $fromDate, $toDate, $sortByColumn = 'rollNo')
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($semId);
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($batchId, $semId);
        if ($isCurrentSem) {
            $sql = "select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, att.staffID, concat(ac.attendanceDate, ac.hour) as attendanceId, ac.sbsID  from attendance_confirm ac inner join  studentaccount sa on sa.batchID = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " order by sa." . $sortByColumn . ", ac.attendanceDate, ac.hour;";
        } else {
            $sql = "select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, att.staffID, concat(ac.attendanceDate, ac.hour) as attendanceId, ac.sbsID  from attendance_confirm ac inner join  studentaccount sa on sa.batchID = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where  joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " union select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, att.staffID, concat(ac.attendanceDate, ac.hour) as attendanceId, ac.sbsID  from attendance_confirm ac inner join failed_students fs on fs.previousBatch = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' left join semesters fsem on fsem.semID = fs.failedInSemester left join studentaccount sa on sa.studentID = fs.studentID left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where  joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and fsem.orderNo > " . $semDetails->orderNo . " order by " . $sortByColumn . ", attendanceDate, hour";
        }
        //         $sql = "select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, att.attendanceDate, hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, staffID, concat(attendanceDate, hour) as attendanceId  from studentaccount sa inner join attendance att on sa.studentID = att.studentID  left join failed_students fs on sa.studentID = fs.studentID left join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where (sa.batchID = $batchId or fs.previousBatch = $batchId) and (fsem.orderNo > $semDetails->orderNo or fsem.orderNo is null) and joinedSem.orderNo <= $semDetails->orderNo and att.batchID = $batchId and att.semID = $semId and attendanceDate between '$fromDate'  and '$toDate' order by sa.$sortByColumn, attendanceDate, hour;";
        try {
            return $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_STUDENT_ATTENDANCE_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get attendance marked dates of a batch in a date range
     * @param int $batchId
     * @param int $semId
     * @param string $fromDate
     * @param string $toDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceMarkedDates($batchId, $semId, $fromDate, $toDate)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $sql = "select DISTINCT(attendanceDate) as attendanceDate from attendance_confirm where semID= $semId and batchID=$batchId and attendanceDate BETWEEN '$fromDate' AND '$toDate' ORDER BY attendanceDate";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get student attendance details in half day session and
     * full day
     * @param int $batchId
     * @param int $semId
     * @param string $fromDate
     * @param string $toDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentAttDetailsBySession($batchId, $semId, $fromDate, $toDate, $sortByColumn = 'rollNo')
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($semId);
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($batchId, $semId);
        if ($isCurrentSem) {
            $sql = "SELECT 
                    studentID,
                    studentName,
                    rollNo,
                    admissionNo,
                    regNo,
                    attendanceDate,
                    attendanceId,
                    batchID,
                    deptID,
                    staffID,
                    COUNT(forenoonLeave) + COUNT(afternoonLeave) AS noOfHrsAbsent,
                    COUNT(present) AS noOfHrsPresent,
                    IF(COUNT(forenoonLeave) > 0
                            AND COUNT(afternoonLeave) > 0,
                        'A',
                        IF(COUNT(forenoonLeave) > 0
                                OR COUNT(afternoonLeave) > 0,
                            'HD',
                            IF(COUNT(present) > 0, 'P', NULL))) AS isAbsent
                FROM
                    (SELECT 
                        sa.studentID,
                            sa.studentAccount,
                            sa.studentName,
                            sa.studentEmail,
                            sa.batchID,
                            sa.deptID,
                            sa.admissionNo,
                            sa.rollNo,
                            sa.regNo,
                            ac.attendanceDate,
                            ac.hour,
                            att.staffID,
                            CONCAT(ac.attendanceDate, ac.hour) AS attendanceId,
                            CASE
                                WHEN isAbsent = 1 AND ac.hour > morninghours THEN 'AN'
                                WHEN isBlocked = 1 AND ac.hour > morninghours THEN 'AN'
                                ELSE null
                            END AS afternoonLeave,
                            CASE
                                WHEN isAbsent = 1 AND ac.hour <= morninghours THEN 'FN'
                                WHEN isBlocked = 1 AND ac.hour <= morninghours THEN 'FN'
                                ELSE null
                            END AS forenoonLeave,
                            CASE
                                WHEN isAbsent = 0 THEN 'P'
                                WHEN isAbsent = 2 THEN 'P'
                                ELSE null
                            END AS present from attendance_confirm ac left join studentaccount sa on sa.batchID = ac.batchID and attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' left join semesters joinedSem on sa.joiningSemId = joinedSem.semID left join attendance att on att.attendanceDate = ac.attendanceDate and sa.studentID = att.studentID and ac.hour = att.hour inner JOIN attendance_rules ar ON ar.batchID = ac.batchID
                        AND ar.semID = ac.semID where ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and joinedSem.orderNo <= " . $semDetails->orderNo . " group by sa.studentID, ac.attendanceDate, ac.hour order by ac.attendanceDate,ac.hour) AS attenTab
                GROUP BY studentID , attendanceDate
                ORDER BY " . $sortByColumn . " , attendanceDate ";
        } else {
            //$sql = "select studentID, studentName, rollNo, admissionNo, regNo ,attendanceDate,attendanceId, batchID, deptID, staffID,count(forenoonLeave)+ count(afternoonLeave) as noOfHrsAbsent, count(present) as noOfHrsPresent, if(count(forenoonLeave)> 0 and count(afternoonLeave) > 0, 'A', if(count(forenoonLeave)> 0 or count(afternoonLeave) > 0, 'HD', if(count(present) > 0 , 'P', null))) as isAbsent from (select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, att.attendanceDate, hour, staffID, concat(attendanceDate, hour) as attendanceId, case when isAbsent = 1  and hour >morninghours then 'AN' when isBlocked = 1  and hour >morninghours then 'AN' end  as afternoonLeave, case when isAbsent = 1  and hour <= morninghours then 'FN' when isBlocked = 1  and hour <= morninghours then 'FN' end as forenoonLeave, case  when isAbsent = 0 then 'P' when isAbsent = 2 then 'P' end as  present from studentaccount sa  left join attendance att on sa.studentID = att.studentID inner join attendance_rules ar on ar.batchID = att.batchID and ar.semID = att.semID left join failed_students fs on sa.studentID = fs.studentID left join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where (sa.batchID = $batchId or fs.previousBatch = $batchId) and (fsem.orderNo > $semDetails->orderNo or fsem.orderNo is null) and joinedSem.orderNo <= $semDetails->orderNo and att.batchID = $batchId and att.semID = $semId and attendanceDate between '$fromDate'  and '$toDate' group by studentID, attendanceDate, hour order by attendanceDate,hour ) as attenTab group by studentID, attendanceDate order by $sortByColumn, attendanceDate";
            $sql = "select studentID, studentName, rollNo, admissionNo, regNo ,attendanceDate,attendanceId, batchID, deptID, staffID,count(forenoonLeave)+ count(afternoonLeave) as noOfHrsAbsent, count(present) as noOfHrsPresent, if(count(forenoonLeave)> 0 and count(afternoonLeave) > 0, 'A', if(count(forenoonLeave)> 0 or count(afternoonLeave) > 0, 'HD', if(count(present) > 0 , 'P', null))) as isAbsent FROM (SELECT 
        sa.studentID,
            sa.studentAccount,
            sa.studentName,
            sa.studentEmail,
            sa.batchID,
            sa.deptID,
            sa.admissionNo,
            sa.rollNo,
            sa.regNo,
            ac.attendanceDate,
            ac.hour,
            att.staffID,
            CONCAT(ac.attendanceDate, ac.hour) AS attendanceId,
            CASE
                WHEN isAbsent = 1 AND ac.hour > morninghours THEN 'AN'
                WHEN isBlocked = 1 AND ac.hour > morninghours THEN 'AN'
                ELSE null
            END AS afternoonLeave,
            CASE
                WHEN isAbsent = 1 AND ac.hour <= morninghours THEN 'FN'
                WHEN isBlocked = 1 AND ac.hour <= morninghours THEN 'FN'
                ELSE null
            END AS forenoonLeave,
            CASE
                WHEN isAbsent = 0 THEN 'P'
                WHEN isAbsent = 2 THEN 'P'
                ELSE null
            END AS present from attendance_confirm ac left join studentaccount sa on sa.batchID = ac.batchID and attendanceDate between '" . $fromDate . "' and '" . $toDate . "' inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID left join attendance att on att.attendanceDate = ac.attendanceDate and sa.studentID = att.studentID and ac.hour = att.hour inner JOIN attendance_rules ar ON ar.batchID = ac.batchID AND ar.semID = ac.semID where ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and joinedSem.orderNo <= " . $semDetails->orderNo . " union  SELECT 
        sa.studentID,
            sa.studentAccount,
            sa.studentName,
            sa.studentEmail,
            sa.batchID,
            sa.deptID,
            sa.admissionNo,
            sa.rollNo,
            sa.regNo,
            ac.attendanceDate,
            ac.hour,
            att.staffID,
            CONCAT(ac.attendanceDate, ac.hour) AS attendanceId,
            CASE
                WHEN isAbsent = 1 AND ac.hour > morninghours THEN 'AN'
                WHEN isBlocked = 1 AND ac.hour > morninghours THEN 'AN'
                ELSE null
            END AS afternoonLeave,
            CASE
                WHEN isAbsent = 1 AND ac.hour <= morninghours THEN 'FN'
                WHEN isBlocked = 1 AND ac.hour <= morninghours THEN 'FN'
                ELSE null
            END AS forenoonLeave,
            CASE
                WHEN isAbsent = 0 THEN 'P'
                WHEN isAbsent = 2 THEN 'P'
                ELSE null
            END AS present from attendance_confirm ac left join failed_students fs on fs.previousBatch = ac.batchID  and attendanceDate between '" . $fromDate . "' and '" . $toDate . "' inner join studentaccount sa on sa.studentID = fs.studentID inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID left join semesters fsem on fsem.semID = fs.failedInSemester left join attendance att on att.attendanceDate = ac.attendanceDate and fs.studentID = att.studentID and ac.hour = att.hour inner JOIN attendance_rules ar ON ar.batchID = ac.batchID AND ar.semID = ac.semID where ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and fsem.orderNo > " . $semDetails->orderNo . " and joinedSem.orderNo <= " . $semDetails->orderNo . " group by studentID, attendanceDate, hour order by attendanceDate,hour) AS attenTab GROUP BY studentID , attendanceDate ORDER BY " . $sortByColumn . " , attendanceDate    ";
        }
        try {
            return $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_STUDENT_ATTENDANCE_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get coninciding students for same Sbs by subbatch
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentCoincidenceAttendanceForSameSbsBySubbatch($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        if ($attendance->subbatchId) {
            $sql = "SELECT DISTINCT sa.studentID, sa.rollNo, sa.regNo, sa.admissionNo,
                sa.studentName,
                sa.batchID,
                att.isAbsent,
                sta.staffName as confirmedStaff,
                sub.subjectDesc
           FROM attendance att
     INNER JOIN studentaccount sa ON sa.studentID = att.studentID AND att.batchID=sa.batchID INNER JOIN attendance_confirm ac ON ac.batchID=att.batchID AND ac.semID=att.semID AND att.sbsID=ac.sbsID AND ac.attendanceDate=att.attendanceDate AND att.hour=ac.hour INNER JOIN sbs_relation sb ON sb.sbsID=att.sbsID INNER JOIN staffaccounts sta ON sta.staffID=sb.staffID INNER JOIN subjects sub ON sub.subjectID=sb.subjectID INNER JOIN subbatch_student ss ON ss.studentID=sa.studentID AND ss.subbatchID=$attendance->subbatchId WHERE att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND att.batchID=$attendance->batchID AND att.semID=$attendance->semID AND att.hour=$attendance->hour ORDER BY sa.$attendance->sortBy";
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentDetails;
    }
    /**
     * check attendance marked or not for a hour
     * @param int $batchId
     * @param int $semId
     * @param int $hour
     * @param string $attendanceDate
     * @param int $subbatchId
     * @return boolean
     * @throws ProfessionalException
     */
    public function isAttendanceMarked($batchId, $semId, $hour, $attendanceDate, $subbatchId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $hour = $this->realEscapeString($hour);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $subbatchId = $this->realEscapeString($subbatchId);
        $isMarked = false;
        $sql = "SELECT sa.staffID FROM attendance_confirm ac INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID INNER JOIN subjects subj ON subj.subjectID=sr.subjectID INNER JOIN staffaccounts sa ON sa.staffID=sr.staffID LEFT JOIN subbatches sb ON sb.subbatchID=ac.subbatchID WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.hour='$hour' AND ac.attendanceDate='" . date('Y-m-d', strtotime($attendanceDate)) . "' AND ac.subbatchID =$subbatchId";
        try {
            $staffId = $this->executeQueryForObject($sql)->staffID;
            if ($staffId) {
                $isMarked = true;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $isMarked;
    }
    /**
     * returns 0 if attendance is marked for the given hour for timetable assigned
     *
     * @param int $deptId
     * @param int $batchId
     * @param int $semId
     * @param string $date
     * @param int $hour
     */
    public function isAttendanceMarkedforHour($deptId, $batchId, $semId, $date, $hour)
    {
        $deptId = $this->realEscapeString($deptId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $date = date('Y-m-d', strtotime($this->realEscapeString($date)));
        /**
         * Checking given date is holiday
         */
        $isHoliday = CalendarService::getInstance()->isHoliday($deptId, $batchId, $date);
        if ($isHoliday) {
            return false;
        }
        $totalStudentsCount = -1;
        $attendanceCount = -1;
        try {
            /**
             * Fetching students count from attendance table by batch, sem, hour and date.
             */
            $sql = "SELECT count(studentID) AS attendanceCount FROM attendance
            WHERE batchID= $batchId AND semID = $semId AND attendanceDate = '" . $date . "' AND hour = '$hour'";
            $attendanceCount = $this->executeQueryForObject($sql)->attendanceCount;
            $attendanceCount = (int) $attendanceCount;
            /**
             * This query returns how much students in time table assigned hour.
             * If time table assigned for a subbatch, then this will be return count of students in subbatch
             * else return strength of all batch
             */
            $sql = "SELECT CASE
            WHEN count(sbss.subbatchID) >0 AND sh.hour IS NULL THEN count(DISTINCT sbst.studentID)
            WHEN count(sbss.subbatchID) =0 AND sh.hour IS NULL THEN count(DISTINCT sa.studentID)
            ELSE 0
            END AS studentCount
            FROM batch_timetable btt
            INNER JOIN batches b ON b.batchID=btt.batchID AND b.semID = btt.semID
            INNER JOIN studentaccount sa ON sa.batchID = b.batchID
            LEFT JOIN suspended_hours sh ON sh.batchID = btt.batchID and sh.semID = btt.semID
            AND sh.suspendedDate = btt.timetableDate AND sh.hour =btt.hourID
            LEFT JOIN sbs_relation sbsr ON sbsr.sbsID = btt.sbsID
            LEFT JOIN subbatch_sbs sbss ON IF (btt.subbatchID, sbss.sbsID = sbsr.sbsID AND sbss.subbatchID = btt.subbatchID,sbss.sbsID = sbsr.sbsID)
            LEFT JOIN subbatch_student sbst ON sbst.subbatchID = sbss.subbatchID AND sbst.studentID NOT IN (SELECT studentID FROM failed_students WHERE previousBatch = $batchId AND isFailNow = 1)
            WHERE btt.batchID= $batchId AND btt.semID = $semId AND btt.timetableDate = '" . $date . "'
            AND btt.hourID =$hour";
            $studentCount = $this->executeQueryForObject($sql)->studentCount;
            $studentCount = (int) $studentCount;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceCount >= $studentCount && $studentCount > 0;
    }
    /**
     * Undocumented function
     *
     * @param [type] $rule
     * @return void
     */
    public function addUpdateAttendanceRule($rule)
    {
        $rule = $this->realEscapeObject($rule);
        if (!$rule->classStartsOn || strtotime($rule->classStartsOn) < 0) {
            $classStartsOn = 'null';
        } else {
            $classStartsOn = "'" . $rule->classStartsOn . "'";
        }
        if (!$rule->classEndsOn || strtotime($rule->classEndsOn) < 0) {
            $classEndsOn = 'null';
        } else {
            $classEndsOn = "'" . $rule->classEndsOn . "'";
        }
        $attendanceRule = $this->getAttendanceRule($rule->batchId, $rule->semId);
        if (empty($attendanceRule)) {
            $sql = "INSERT INTO attendance_rules (batchID, semID, morninghours, dateOfjoining, classStartsFrom, classEnds, isActive, halfdayHourCount, fulldayHourCount) VALUES(" . $rule->batchId . ", " . $rule->semId . ", " . $rule->morninghours . ", " . $rule->dateOfjoining . ", " . $classStartsOn . "," . $classEndsOn . ",'1', '$rule->halfdayHourCount', '$rule->fulldayHourCount')";
        } else {
            $sql = "UPDATE attendance_rules SET morninghours = " . $rule->morninghours . ",dateOfjoining = " . $rule->dateOfjoining . ", classStartsFrom = " . $classStartsOn . ", classEnds = " . $classEndsOn . ", halfdayHourCount='$rule->halfdayHourCount', fulldayHourCount='$rule->fulldayHourCount'  WHERE batchID = " . $rule->batchId . " AND semID = " . $rule->semId . "";
        }
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * Undocumented function
     *
     * @param [type] $staffId
     * @param [type] $startDate
     * @param [type] $endDate
     * @return void
     */
    public function getUnmarkedHourAndDateDetails($staffId, $startDate, $endDate)
    {
        $unmarkedDetails = [];
        $totalUnmarkedHourAndDateDetails = [];
        $totalMarkedHourAndDateDetails = [];
        $totalUnAssignedHourAndDateDetails = [];
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $staffId = $this->realEscapeString($staffId);
        $staffName = StaffService::getInstance()->getStaffDetailsById($staffId)[0]->staffName;
        try {
            if (!$startDate || !$endDate || !$staffId) {
                throw new ProfessionalException(ProfessionalException::METHOD_PARAMETER_NULL, "METHOD_PARAMETER_NULL");
            } else {
                // getTotalHourDetailsOfFaculty
                $totalDateDetails = $this->getTotalHourDetailsOfFaculty($staffId, $startDate, $endDate);
                // var_dump($totalDateDetails);
                if (!empty($totalDateDetails)) {
                    foreach ($totalDateDetails as $dateDetail) {
                        $unmarkedDetails = $this->getUnmarkedHourAndDate($staffId, $dateDetail->date, $dateDetail->hourId);
                        //    var_dump($unmarkedDetails);
                        if ($unmarkedDetails == NULL) {
                            $isSuspendedHour = null;
                            $isSuspendedHour = $this->isSuspendedHourForBatch($dateDetail->date, $dateDetail->hourId, $dateDetail->batchId, $dateDetail->semId);
                            if (!$isSuspendedHour) {
                                $attendance = new Attendance();
                                $attendance->attendanceId = $dateDetail->id;
                                $attendance->attendanceDate = $dateDetail->date;
                                $attendance->staff = $staffName;
                                $attendance->hour = $dateDetail->hourId;
                                $markedInfo = $this->checkSbsIDForMarkedStaff($dateDetail->batchId, $dateDetail->semId, $dateDetail->hourId, $dateDetail->date);
                                //    $hai = $markedInfo;
                                if ($markedInfo != NULL) {
                                    $markedStaffSbsId = $markedInfo->sbsID;
                                    if ($markedStaffSbsId != $dateDetail->sbsId) {
                                        $attendance->MarkedStaff = StaffService::getInstance()->getStaffDetailsBysbsID($markedStaffSbsId)->name;
                                    } else {
                                        $attendance->MarkedStaff = "NA";
                                    }
                                } else {
                                    $attendance->MarkedStaff = "NA";
                                }
                                $totalUnmarkedHourAndDateDetails[] = $attendance;
                            }
                        }
                        //    else
                        //    {
                        //         $attendance = new Attendance();
                        //        $attendance->attendanceId = $dateDetail->id;
                        //        $attendance->attendanceDate = $dateDetail->date;
                        //        $attendance->staff = $staffId;
                        //        $attendance->hour = $dateDetail->hourId ;
                        //        $totalMarkedHourAndDateDetails [] = $attendance;
                        //    }
                    }
                    $totalMarkedHourAndDateDetails = $this->getMarkedHourDetailsWithFaculty($startDate, $endDate, $staffId, $staffName);
                    $sbsIdObjects = StaffService::getInstance()->getsbsIDsBystaffID($staffId);
                    foreach ($sbsIdObjects as $sbsObject) {
                        $sbsIDs[] = $sbsObject->sbsID;
                    }
                    if (!empty($sbsIDs)) {
                        foreach ($totalMarkedHourAndDateDetails as $assignedMarkedDetails) {
                            if ($assignedMarkedDetails->sbsID != NULL && !(in_array($assignedMarkedDetails->sbsID, $sbsIDs))) {
                                $totalUnAssignedHourAndDateDetails[] = $assignedMarkedDetails;
                            }
                        }
                    }
                }
                // var_dump($totalMarkedHourAndDateDetails);
            }
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        $response = new \stdClass();
        $response->unmarkedHourandDate = $totalUnmarkedHourAndDateDetails;
        $response->markedHourandDate = $totalMarkedHourAndDateDetails;
        $response->unassignedMarkedHour = $totalUnAssignedHourAndDateDetails;
        return $response;
    }
    /**
     * Undocumented function
     *
     * @param [type] $staffId
     * @param [type] $checkDate
     * @param [type] $hour
     * @return void
     */
    public function getUnmarkedHourAndDate($staffId, $checkDate, $hour)
    {
        $totalUnMarkedHourDetails = NULL;
        $checkDate = $this->realEscapeString($checkDate);
        $hour = $this->realEscapeString($hour);
        $staffId = $this->realEscapeString($staffId);
        try {
            if (!$checkDate || !$hour || !$staffId) {
                throw new ProfessionalException(ProfessionalException::METHOD_PARAMETER_NULL, "METHOD_PARAMETER_NULL");
            } else {
                $sql = "SELECT hour,attendanceDate FROM attendance_confirm WHERE sbsID in (select DISTINCT t1.sbsID from sbs_relation t1, batches t2 where t1.batchID=t2.batchID and t1.semID=t2.semID and t1.staffID=$staffId) and attendanceDate =\"$checkDate\" and hour=$hour";
                $totalUnMarkedHourDetails = $this->executeQueryForObject($sql);
            }
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        return $totalUnMarkedHourDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $date
     * @param [type] $hour
     * @param [type] $batchId
     * @param [type] $semId
     * @return boolean
     */
    public function isSuspendedHourForBatch($date, $hour, $batchId, $semId)
    {
        $date = $this->realEscapeString($date);
        $hour = $this->realEscapeString($hour);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $query = "select * from suspended_hours where suspendedDate ='$date' and hour='$hour' and batchID='$batchId' and semID='$semId';";
        try {
            $response = $this->executeQueryForObject($query);
            return $response;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Undocumented function
     *
     * @param [type] $fromdate
     * @param [type] $todate
     * @param [type] $batchId
     * @param [type] $semId
     * @return boolean
     */
    public function getSuspendedHoursBetweenDates($fromDate, $toDate, $batchId, $semId)
    {
        $fromdate = $this->realEscapeString($fromDate);
        $todate = $this->realEscapeString($toDate);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $query = "select hour,suspendedDate from suspended_hours where suspendedDate between '" . $fromdate . "'  and '" . $todate . "'and batchID='$batchId' and semID='$semId';";
        try {
            $response = $this->executeQueryForList($query);
            return $response;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Undocumented function
     *
     * @param [type] $batchID
     * @param [type] $semID
     * @param [type] $hourID
     * @param [type] $checkDate
     * @return void
     */
    public function checkSbsIDForMarkedStaff($batchID, $semID, $hourID, $checkDate)
    {
        $sbsDetails = NULL;
        $sql = "SELECT sbsID  FROM attendance_confirm where batchID=$batchID and semID=$semID and hour =$hourID and attendanceDate =\"$checkDate\"";
        // echo $sql;
        try {
            $sbsDetails = $this->executeQueryForObject($sql);
            // var_dump($sbsDetails);
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        return $sbsDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $staffId
     * @param [type] $startDate
     * @param [type] $endDate
     * @return void
     */
    public function getTotalHourDetailsOfFaculty($staffId, $startDate, $endDate)
    {
        $totalHourDetails = [];
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $staffId = $this->realEscapeString($staffId);
        try {
            if (!$startDate || !$endDate || !$staffId) {
                throw new ProfessionalException(ProfessionalException::METHOD_PARAMETER_NULL, "METHOD_PARAMETER_NULL");
            } else {
                $sql = "SELECT timetableID as id,hourID as hourId,timetableDate as date,batchID as batchId,semID as semId,sbsID as sbsId FROM batch_timetable  WHERE sbsID in (select DISTINCT t1.sbsID from sbs_relation t1, batches t2 where t1.batchID=t2.batchID and t1.semID=t2.semID and t1.staffID=$staffId) and timetableDate  between '$startDate' and '$endDate'";
                $totalHourDetails = $this->executeQueryForList($sql);
            }
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        return $totalHourDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $batchID
     * @param [type] $semID
     * @param [type] $hourID
     * @param [type] $checkDate
     * @return void
     */
    public function checkSbsID($batchID, $semID, $hourID, $checkDate)
    {
        $sbsDetails = NULL;
        $sql = "SELECT timetableID as id,sbsID as sbsId,timetableDate as date,hourID as hourId FROM batch_timetable where batchID=$batchID and semID=$semID and hourID =$hourID and timetableDate =\"$checkDate\"";
        // echo $sql;
        try {
            $sbsDetails = $this->executeQueryForObject($sql);
            // var_dump($sbsDetails);
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        return $sbsDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $startDate
     * @param [type] $endDate
     * @param [type] $staffId
     * @param [type] $staffName
     * @return void
     */
    public function getMarkedHourDetailsWithFaculty($startDate, $endDate, $staffId, $staffName)
    {
        $totalMarkedHourDetails = [];
        $totalMarkedHourAndDateDetails = [];
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $staffId = $this->realEscapeString($staffId);
        try {
            if (!$startDate || !$endDate || !$staffId) {
                throw new ProfessionalException(ProfessionalException::METHOD_PARAMETER_NULL, "METHOD_PARAMETER_NULL");
            } else {
                $sql = "SELECT  hour,attendanceDate ,sbsID,batchID,semID FROM attendance_confirm WHERE sbsID in (select DISTINCT t1.sbsID from sbs_relation t1, batches t2 where t1.batchID=t2.batchID and t1.semID=t2.semID and t1.staffID=$staffId) and attendanceDate  between '$startDate' and '$endDate'";
                // echo $sql;
                $totalMarkedHourDetails = $this->executeQueryForList($sql);
                if (!empty($totalMarkedHourDetails)) {
                    foreach ($totalMarkedHourDetails as $details) {
                        $sbsObject = $this->checkSbsID($details->batchID, $details->semID, $details->hour, $details->attendanceDate);
                        if ($sbsObject != NULL) {
                            $originalSbsID = $sbsObject->sbsId;
                            if ($originalSbsID == $details->sbsID) {
                                $attendance = new Attendance();
                                $attendance->attendanceId = $sbsObject->id;
                                $attendance->attendanceDate = $sbsObject->date;
                                $attendance->staff = $staffName;
                                $attendance->hour = $sbsObject->hourId;
                                $attendance->MarkedStaff = $staffName;
                                $totalMarkedHourAndDateDetails[] = $attendance;
                            } else {
                                $attendance = new Attendance();
                                $attendance->attendanceId = $sbsObject->id;
                                $attendance->attendanceDate = $sbsObject->date;
                                $attendance->staff = StaffService::getInstance()->getStaffDetailsBysbsID($originalSbsID)->name;
                                $attendance->hour = $sbsObject->hourId;
                                $attendance->MarkedStaff = $staffName;
                                $attendance->sbsID = $originalSbsID;
                                $totalMarkedHourAndDateDetails[] = $attendance;
                            }
                        }
                    }
                }
            }
        } catch (\Exception $ex) {
            throw new ProfessionalException($ex->getCode(), $ex->getMessage());
        }
        return $totalMarkedHourAndDateDetails;
    }
    /**
     * Undocumented function
     *
     * @param GetStudentAttendanceRequest $request
     * @return void
     */
    public function getStudentsAttendanceByDate($request)
    {
        $studentAttendanceList = null;
        $sortBy = "";
        $sql = "select sta.studentID as studentId,sta.studentName as studentName,
sta.batchID as batchId,sta.rollNo as rollNo,a.isAbsent as isAbsent,sa.staffID as staffId,sa.staffName as staffName,a.hour ,a.batchID as batchId,a.semID as semId,concat(a.studentID,a.hour,a.attendanceDate,a.batchID,a.semID) as attendanceId,dlr.dlrId,dlr.dlrName,dlr.dlrDescription
                     FROM studentaccount sta 
                        LEFT JOIN  attendance a on a.studentID = sta.studentID and a.attendanceDate='$request->attendanceDate'  and a.semID='$request->semId
                        INNER JOIN  staffaccounts sa on sa.staffID = a.staffID 
                        INNER JOIN sbs_relation sr on sr.sbsID = a.sbsID
                        LEFT JOIN duty_leave_remarks dlr on dlr.dlrID = a.dlrID
                        WHERE  sta.batchID='$request->batchId'  ";
        $sortBy = empty($request->sortBy) ? (" studentName " . $request->sortOrder) : (" " . $request->sortBy . "  " . $request->sortOrder);
        $sql .= " ORDER BY " . $sortBy;
        try {
            $studentAttendanceList = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_STUDENT_ATTENDANCE_MAPPER]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentAttendanceList;
    }
    /**
     * Method for returning an array of hour object
     *
     * @param integer $numberOfHours
     * @return array
     * @author gadheyan
     */
    public function getCollegeDefinedHours()
    {
        global $ATTENDANCE_HOURS;
        $hourArray = [];
        $hour = null;
        for ($i = 1; $i <= $ATTENDANCE_HOURS; $i++) {
            $hour = new Hour();
            $hour->hourId = $i;
            $hour->hourName = "Hour " . $i;
            $hourArray[] = $hour;
        }
        return $hourArray;
    }
    /**
     * Undocumented function
     *
     * @param [type] $staffID
     * @param [type] $batchID
     * @return void
     */
    public function staffPrivilege($staffID, $batchID)
    {
        $response = null;
        $staffID = $this->realEscapeString($staffID);
        $batchID = $this->realEscapeString($batchID);
        $query = "select * from duty_leave_privileges where staffID=$staffID and batchID=$batchID";
        try {
            $response = $this->executeQueryForObject($query);
            return $response;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Method to validate duty leave remark object
     *
     * @param DutyLeaveRemarks $dlr
     * @throws ProfessionalException
     * @author Gadheyan
     */
    private function validateDutyLeaveRemarksObject($dlr)
    {
        if ($dlr != NULL) {
            if ($dlr->dlrName == NULL) {
                throw new ProfessionalException(ProfessionalException::DUTY_LEAVE_REMARK_NAME_NOT_DEFINED, "Duty Leave Remark Name is NULL");
            }
        } else {
            throw new ProfessionalException(ProfessionalException::DUTY_LEAVE_REMARK_OBJECT_NOT_DEFINED, "Duty Leave Remark object is NULL");
        }
    }
    /**
     * Method for inserting duty leave remarks to duty_leave_remarks table.
     *
     * @param DutyLeaveRemarks $dlr
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     * @author Gadheyan
     */
    public function addDutyLeaveRemarks($dlr)
    {
        $sql = "";
        $lastInsertedId = NULL;
        $this->validateDutyLeaveRemarksObject($dlr);
        foreach ($dlr as $key => $value) {
            $dlr->$key = $this->realEscapeString($value);
        }
        try {
            $sql = "INSERT INTO duty_leave_remarks(dlrName,dlrDescription) VALUES('" . $dlr->dlrName . "','" . $dlr->dlrDescription . "')";
            $lastInsertedId = $this->executeQuery($sql, 'TRUE');
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $lastInsertedId;
    }
    /**
     * Method for deleting a particular duty leave remark entry.
     *
     * @param string $dlrId
     * @throws ProfessionalException
     * @author gadheyan
     */
    public function deleteDutyLeaveRemarks($dlrId)
    {
        $sql = "";
        if ($dlrId == NULL) {
            throw new ProfessionalException(ProfessionalException::DUTY_LEAVE_REMARK_ID_NOT_DEFINED, "DUTY_LEAVE_REMARK_ID_NOT_DEFINED");
        }
        $dlrId = $this->realEscapeString($dlrId);
        try {
            $sql = "DELETE FROM duty_leave_remarks WHERE dlrId=" . $dlrId;
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::QUERY_EXECUTION_FAILED, $e->getMessage());
        }
    }
    /**
     * Method for updating a particular duty leave remarks entry
     *
     * @param DutyLeaveRemarks $dlr
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     * @author gadheyan
     */
    public function updateDutyLeaveRemarks($dlr)
    {
        $sql = "";
        $this->validateDutyLeaveRemarksObject($dlr);
        if ($dlr->dlrId == NULL) {
            throw new ProfessionalException(ProfessionalException::DUTY_LEAVE_REMARK_ID_NOT_DEFINED, "DUTY_LEAVE_REMARK_ID_NOT_DEFINED");
        }
        foreach ($dlr as $key => $value) {
            $dlr->$key = $this->realEscapeString($value);
        }
        try {
            $sql = "UPDATE duty_leave_remarks SET dlrName='" . $dlr->dlrName . "', dlrDescription='" . $dlr->dlrDescription . "' WHERE dlrId=" . $dlr->dlrId;
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::QUERY_EXECUTION_FAILED, $e->getMessage());
        }
    }
    /**
     * Get all duty leave remarks in database
     *
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     * @author gadheyan
     */
    public function getAllDutyLeaveRemarks()
    {
        $sql = "";
        $dlrArray = [];
        try {
            $sql = "SELECT dlrId, dlrName, dlrDescription FROM duty_leave_remarks";
            $dlrArray = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $dlrArray;
    }
    /**
     * Method for fetching attendance detail of students of a batch in a particular semester
     * along with duty leave remark reasons.
     *
     * @param integer $semID
     * @param integer $batchID
     * @param date $attendanceDate
     * @param integer $hour
     * @return object|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     * @author gadheyan
     */
    public function getDutyLeaveRemarksDetailsForStudents($batchID, $attendanceDate, $hour, $semID)
    {
        $sql = "";
        $dlrArray = [];
        $batchID = $this->realEscapeString($batchID);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $hour = $this->realEscapeString($hour);
        try {
            $sql = "SELECT at.studentID,at.isAbsent,at.hour,at.attendanceDate,st.studentName,st.rollNo,dlr.dlrName,dlr.dlrDescription,at.dlrId FROM attendance at INNER JOIN studentaccount st ON at.studentID=st.studentID LEFT JOIN duty_leave_remarks dlr ON at.dlrId=dlr.dlrId WHERE at.attendanceDate=\"$attendanceDate\" AND at.batchID=$batchID AND at.semID=$semID AND at.hour=$hour ORDER BY st.rollNo";
            $dlrArray = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::QUERY_EXECUTION_FAILED, $e->getMessage());
        }
        return $dlrArray;
    }
    public function grantDutyLeaveHourWise($batchID, $semID, $fromDate, $hrs, $studentIDs, $dutyLeaveRemarkId, $toDate,$attStatus,$hourCount)
    {
        $batchID = $this->realEscapeString($batchID);
        $semID = $this->realEscapeString($semID);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $dutyLeaveRemarkId = $this->realEscapeString($dutyLeaveRemarkId);
        $studentIDs = $this->realEscapeString($studentIDs);
        $hrs = $this->realEscapeString($hrs);
        if($attStatus){
            $sqlAttStatus = "";
            $sqlAttStatus = !$attStatus->absent && $attStatus->present ?" AND isAbsent = '0' ":$sqlAttStatus;
            $sqlAttStatus = $attStatus->absent && !$attStatus->present ?" AND isAbsent = '1' ":$sqlAttStatus;
            $sqlAttStatus = $attStatus->absent && $attStatus->present ?" AND isAbsent in ('0','1') ":$sqlAttStatus;
        }
        $sql_stu = "";
        if ($studentIDs == 'all') {
            $sql_stu = " AND studentID IN(SELECT studentID FROM studentaccount WHERE batchID=\"$batchID\" ORDER BY rollNo)";
        } else if ($studentIDs != null) {
            $stdIDs = explode(",", $studentIDs);
            $sql_stu = " AND studentID IN(" . implode(',', $stdIDs) . ")";
        }
        $sql_hrs = "";
        if ($hrs == 'all') {
            for($i=1;$i<=$hourCount;$i++){$hours[] = $i;}
        } else {
            $hours = explode(",", $hrs);
        }
        $sql_hrs = "and  hour in(" . implode(',', $hours) . ")";
        // echo $studentID;
        if ($sql_stu) {
            try {
                $sql = "UPDATE attendance SET isAbsent='2',dlrId=$dutyLeaveRemarkId  WHERE batchID=" . $batchID . " AND semID=" . $semID . " and attendanceDate between '$fromDate' and '$toDate$sql_hrs $sql_stu $sqlAttStatus";
                $result_up = $this->executeQueryForObject($sql, TRUE);
                return "success";
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
        }
    }
    /**
     *
     *
     * @return void
     */
    public function getLeaveTypeIdOfDutyLeave()
    {
        $sql = "";
        $sql = "SELECT id FROM student_leave_type WHERE isDl=1 and isActive=1";
        $dutyLeaveId = NULL;
        try {
            $dutyLeaveId = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (empty($dutyLeaveId)) {
            return null;
        }
        return $dutyLeaveId->id;
    }
    /**
     *    get all id's of duty leave type
     *
     * @return Array
     */
    public function getAllLeaveTypeIdsOfDutyLeave()
    {
        $sql = "";
        $sql = "SELECT id FROM student_leave_type WHERE isDl=1 and isActive=1";
        $dutyLeaveIdList = NULL;
        try {
            $dutyLeaveIdList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (empty($dutyLeaveIdList)) {
            return null;
        }
        $dutyLeaveIdArray = [];
        foreach ($dutyLeaveIdList as $dutyLeaveId) {
            $dutyLeaveIdArray[] = $dutyLeaveId->id;
        }
        return $dutyLeaveIdArray;
    }
    /**
     * Get attendance edit privilege of staff
     * @param int $staffId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAttendanceEditPrivilege($staffId)
    {
        $sql = "";
        $staffId = $this->realEscapeString($staffId);
        try {
            $sql = "select id as privilageID,staffID FROM attendance_edit_privilage where staffID = " . $staffId . "";
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Create attendance edit privilege of staff
     * @param AttendanceEditPrivilege $attendancePrivilege
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function createAttendanceEditPrivilege($attendancePrivilege)
    {
        $attendancePrivilege = $this->realEscapeObject($attendancePrivilege);
        foreach ($attendancePrivilege->staffId as $staffId) {
            if (!$this->getAttendanceEditPrivilege($staffId)) {
                $values[] = "(" . $staffId . ", " . $attendancePrivilege->deptId . ", " . $attendancePrivilege->createdBy . ", UTC_TIMESTAMP(), " . $attendancePrivilege->updatedBy . ", UTC_TIMESTAMP())";
            }
        }
        if ($values) {
            $sql = "INSERT INTO attendance_edit_privilage (staffID, deptID, createdBy, createdDate, updatedBy, updatedDate) VALUES " . implode(", ", $values) . "";
            try {
                return $this->executeQueryForObject($sql);
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
        }
    }
    /**
     * Delete attendance edit privilege
     * @param array $staffIds
     * @return unknown
     * @throws ProfessionalException
     */
    public function deleteAttendanceEditPrivilege($staffIds)
    {
        $staffIds = $this->realEscapeArray($staffIds);
        $sql = "DELETE FROM attendance_edit_privilage WHERE staffID in (" . implode(",", $staffIds) . ")";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get attendance edit privilege of staff
     * @param int $staffId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAllAttendanceEditPrivilege($deptId)
    {
        $sql = "";
        $deptId = $this->realEscapeString($deptId);
        try {
            $sql = "select id as privilageID,staffID FROM attendance_edit_privilage where deptID = " . $deptId . "";
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete students from attendance temp other than this batch or migrated from this batch
     * @param Attendance $attendance
     */
    public function deleteStudentsFromAttendanceTempOtherBatch($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        try {
            $sql_mig = "DELETE att.* from attendance_temporary att INNER JOIN studentaccount sa ON sa.studentID=att.studentID INNER JOIN batches bt ON bt.batchID=sa.batchID INNER JOIN sbs_relation sr ON sr.sbsID=att.sbsID WHERE sa.batchID=$attendance->batchID AND att.hour=$attendance->hour AND att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND bt.semID=$attendance->semID AND sr.batchID !=$attendance->batchID";
            $sql_old = "DELETE att.* from attendance_temporary att INNER JOIN studentaccount sa ON sa.studentID=att.studentID INNER JOIN batches bt ON att.batchID=bt.batchID INNER JOIN sbs_relation sr ON sr.sbsID=att.sbsID WHERE att.batchID=$attendance->batchID AND att.hour=$attendance->hour AND att.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND bt.semID=$attendance->semID AND sa.batchID !=$attendance->batchID";
            $this->executeQuery($sql_mig);
            return $this->executeQuery($sql_old);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * add Attednance log
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function addAttendanceLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        $sql = "INSERT INTO attendance_log (attendanceDate, hour, subjectId, batchId, semId, subbatchId, sbsId, isMarked, markedSubbatchId, markedStaffId, markedSubjectId, psId, createdBy, createdDate, updatedBy, updatedDate) VALUES ('" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "', $attendanceLog->hour$attendanceLog->subjectId$attendanceLog->batchId$attendanceLog->semId$attendanceLog->subbatchId$attendanceLog->sbsId$attendanceLog->isMarked$attendanceLog->markedSubbatchId$attendanceLog->markedStaffId$attendanceLog->markedSubjectId$attendanceLog->psId$attendanceLog->createdBy, utc_timestamp(), $attendanceLog->updatedBy, utc_timestamp())";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete attendance log
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function removeAttendanceLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        $sql = "DELETE FROM attendance_log WHERE attendanceDate='" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "' AND batchId=$attendanceLog->batchId AND semId=$attendanceLog->semId ";
        if ($attendanceLog->hour) {
            $sql .= "AND hour=$attendanceLog->hour ";
        }
        if ($attendanceLog->sbsId) {
            $sql .= "AND sbsId=$attendanceLog->sbsId ";
        }
        if ($attendanceLog->isMarked != NULL) {
            $sql .= "AND isMarked=$attendanceLog->isMarked ";
        }
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * add attendance log from timetable
     * @param Timetable $timetable
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function addAttendanceLogFromTimeTable($timetable)
    {
        $timetable = $this->realEscapeObject($timetable);
        $sql = "INSERT INTO attendance_log (attendanceDate, hour, subjectId, batchId, semId, subbatchId, sbsId, isMarked, markedForAll, markedSubbatchId, markedStaffId, markedSubjectId, psId, createdBy, createdDate, updatedBy, updatedDate) SELECT bt.timetableDate, bt.hourID, bt.subjectID, bt.batchID, bt.semID, if(ss.subbatchID,ss.subbatchID,0) as subbatchID, bt.sbsID,if(ac.sbsID,1,0) as isMarked, if(ac.subbatchID=0,1,0) as MarkedForAll, ac.subbatchID, sr.staffID, sr.subjectID, sb.psID, 1, utc_timestamp(), 1, utc_timestamp() from batch_timetable bt LEFT JOIN subbatch_sbs ss ON bt.sbsID=ss.sbsID LEFT JOIN subbatches sb ON sb.subbatchID=ss.subbatchID LEFT JOIN attendance_confirm ac ON ac.attendanceDate=bt.timetableDate AND ac.hour=bt.hourID AND bt.batchID=ac.batchID AND bt.semID=ac.semID LEFT JOIN sbs_relation sr ON sr.sbsID=ac.sbsID where bt.timetableDate='" . date('Y-m-d', strtotime($timetable->timetableDate)) . "' ";
        if ($timetable->batchID) {
            $sql .= "AND bt.batchID=$timetable->batchID ";
        }
        if ($timetable->semID) {
            $sql .= "AND bt.semID=$timetable->semID ";
        }
        if ($timetable->hourID) {
            $sql .= "AND bt.hourID=$timetable->hourID ";
        }
        if ($timetable->sbsID) {
            $sql .= "AND bt.sbsID=$timetable->sbsID ";
        }
        $sql .= "order by bt.timetableID";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update attendance log after confrim attendance
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function updateAttendanceConfirmLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        $sql = "UPDATE attendance_log SET isMarked=$attendanceLog->isMarked, markedSubbatchId=$attendanceLog->markedSubbatchId, markedSubjectId=$attendanceLog->markedSubjectId, markedStaffId=$attendanceLog->markedStaffId, updatedBy=$attendanceLog->updatedBy, updatedDate=utc_timestamp() WHERE batchId=$attendanceLog->batchId AND semId=$attendanceLog->semId AND attendanceDate='" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "' AND hour=$attendanceLog->hour AND subbatchId=$attendanceLog->subbatchId AND isMarked=0";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * update attendance marked for all
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function updateAttendanceMarkedForAllLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        if ($attendanceLog->subbatchId) {
            $markedFor = "markedForAllSubbatch=$attendanceLog->markedForAllSubbatch";
        } else {
            $markedFor = "markedForAll=$attendanceLog->markedForAll";
        }
        $sql = "UPDATE attendance_log SET $markedFor WHERE attendanceDate='" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "' AND hour=$attendanceLog->hour AND batchId=$attendanceLog->batchId AND semId=$attendanceLog->semId ";
        if ($attendanceLog->subbatchId) {
            $sql .= "AND subbatchId=$attendanceLog->subbatchId";
        }
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get attendance not cofirmed attendance log
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function getUnmarkedAttendanceLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        $sql = "SELECT id FROM attendance_log WHERE isMarked=0 AND attendanceDate='" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "' AND hour=$attendanceLog->hour AND sbsId=$attendanceLog->sbsId AND subbatchId=$attendanceLog->subbatchId";
        try {
            return $this->executeQueryForObject($sql)->id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete attendance confirmed attendanceLog
     * @param AttendanceLog $attendanceLog
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function removeMarkedAttendanceLog($attendanceLog)
    {
        $attendanceLog = $this->realEscapeObject($attendanceLog);
        $sql = "DELETE FROM attendance_log WHERE attendanceDate='" . date('Y-m-d', strtotime($attendanceLog->attendanceDate)) . "' AND markedStaffId=$attendanceLog->markedStaffId AND markedSubjectId=$attendanceLog->markedSubjectId  AND batchId=$attendanceLog->batchId AND semId=$attendanceLog->semId ";
        if ($attendanceLog->markedSubbatchId != NULL) {
            $sql .= "AND markedSubbatchId=$attendanceLog->markedSubbatchId ";
        }
        if ($attendanceLog->hour) {
            $sql .= "AND hour=$attendanceLog->hour";
        }
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * add attendance log after delete attendance
     * @param Timetable $timetable
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function addAttendanceLogAfterAttendanceDelete($timetable)
    {
        $timetable = $this->realEscapeObject($timetable);
        $sql = "INSERT INTO attendance_log (attendanceDate, hour, subjectId, batchId, semId, subbatchId, sbsId, isMarked, markedForAll, markedForAllSubbatch, markedSubbatchId, markedStaffId, markedSubjectId, psId, createdBy, createdDate, updatedBy, updatedDate) SELECT bt.timetableDate, bt.hourID, bt.subjectID, bt.batchID, bt.semID, if(ss.subbatchID,ss.subbatchID,0)as subbatchID, bt.sbsID,if(ac.sbsID,1,0) as isMarked, if(ac.subbatchID=0,1,0) as MarkedForAll, if(ss.subbatchID=ac.subbatchID,1,0) as markedForAllSubbatch, ac.subbatchID, sr.staffID, sr.subjectID, if(sub.psID,sub.psID,0) as psID, 1, utc_timestamp(), 1, utc_timestamp()  from batch_timetable bt LEFT JOIN subbatch_sbs ss ON bt.sbsID=ss.sbsID LEFT JOIN subbatches sub ON sub.subbatchID=ss.subbatchID LEFT JOIN attendance_confirm ac ON ac.attendanceDate=bt.timetableDate AND ac.hour=bt.hourID AND bt.batchID=ac.batchID AND bt.semID=ac.semID LEFT JOIN sbs_relation sr ON sr.sbsID=ac.sbsID LEFT JOIN attendance_log al ON al.batchId=bt.batchID AND al.semId=bt.semID AND al.sbsId=bt.sbsID AND al.attendanceDate=bt.timetableDate AND bt.hourID=al.hour WHERE bt.timetableDate='" . date('Y-m-d', strtotime($timetable->timetableDate)) . "' AND bt.batchID=$timetable->batchID AND bt.semID=$timetable->semID AND al.id is null ";
        if ($timetable->hourID) {
            $sql .= "AND bt.hourID=$timetable->hourID ";
        }
        $sql .= "ORDER BY bt.timetableID";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get unmarked student from batch or subbatch
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function isUnmarkedStudentAfterConfirm($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($attendance->semID);
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($attendance->batchID, $attendance->semID);
        if ($attendance->subbatchId) {
            if ($isCurrentSem) {
                $sql = "select count(sta.studentID) as unmarkedStudents from studentaccount sta inner join  subbatch_student substu on sta.studentID=substu.studentID inner join semesters joinSem on joinSem.semID = sta.joiningSemId inner join batches ba on ba.batchID = sta.batchID inner join semesters sem on sem.semID = ba.semID  where  substu.subbatchID=$attendance->subbatchId AND joinSem.orderNo <= sem.orderNo AND sta.studentID NOT IN(select t1.studentID from studentaccount t1, subbatch_student t2, attendance t3 where t2.subbatchID=\"" . $attendance->subbatchId . "\" and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=\"" . $attendance->hour . "\" and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=\"" . $attendance->batchID . "\" and t3.semID=\"" . $attendance->semID . "\")";
            } else {
                $sql = "select count(studentID) as unmarkedStudents from (select sta.studentID from studentaccount sta inner join subbatch_student substu on sta.studentID=substu.studentID inner join semesters joinSem on joinSem.semID = sta.joiningSemId where substu.subbatchID=$attendance->subbatchId AND sta.batchID='$attendance->batchID' and joinSem.orderNo <= $semDetails->orderNo union select fs.studentID from failed_students fs inner join subbatch_student sub on fs.studentID=sub.studentID inner join studentaccount sa ON sa.studentID=sub.studentID inner join semesters fSem on fSem.semID = fs.failedInSemester  where sub.subbatchID=$attendance->subbatchId AND fs.previousBatch = $attendance->batchID and fSem.orderNo > $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from studentaccount t1, subbatch_student t2, attendance t3 where t2.subbatchID=$attendance->subbatchId and t1.studentID=t2.studentID and t2.studentID=t3.studentID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.batchID=$attendance->batchID and t3.semID=$attendance->semID)";
            }
        } else {
            if ($isCurrentSem) {
                $sql = "select  count(studentID) as unmarkedStudents from studentaccount sa inner join batches ba on sa.batchID =  ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where ba.batchID=$attendance->batchID AND joinedSem.orderNo <= sem.orderNo AND studentID NOT IN(select t1.studentID from  studentaccount t1, attendance t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID)";
            } else {
                $sql = "select  count(studentID) as unmarkedStudents from (select studentID from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where sa.batchID=$attendance->batchID AND joinedSem.orderNo <= $semDetails->orderNo union select fs.studentID from failed_students fs inner join studentaccount sa ON sa.studentID=fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from  studentaccount t1, attendance t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID)";
            }
        }
        try {
            return $this->executeQueryForObject($sql)->unmarkedStudents;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Method for getting lock period details for a batchId
     * @param Attendance $attendance
     * @author Ranjith Balachandran
     */
    public function getLockPeriodDetails($batchId)
    {
        $sql = null;
        $lockPeriodDetails = null;
        $batchId = $this->realEscapeString($batchId);
        try {
            $sql = "SELECT allowLockLimitHod FROM attendance_limit WHERE batchID = $batchId";
            $lockPeriodDetails = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $lockPeriodDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $batchId
     * @param [type] $semId
     * @param [type] $attendanceFromDate
     * @param [type] $attendanceToDate
     * @param [type] $hour
     * @return void
     */
    public function getAttendanceConfirmedStaffDetailsForAGivenDateRange($batchId, $semId, $attendanceFromDate, $attendanceToDate, $hour = NULL, $subbatchId = 0, $sbsId = null)
    {
        $staffDetails = NULL;
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $attendanceFromDate = $this->realEscapeString($attendanceFromDate);
        $attendanceToDate = $this->realEscapeString($attendanceToDate);
        $hour = $this->realEscapeString($hour);
        $subbatchId = $this->realEscapeString($subbatchId);
        $sbsId = $this->realEscapeString($sbsId);
        $sql = "SELECT sa.staffID, ac.subbatchID, if(sb.subbatchName !='',sb.subbatchName,'All') as subbatchName
, sr.sbsID, sa.staffName, ac.confirmedDate, ac.exam_id as examId, subj.subjectDesc, subj.subjectName FROM attendance_confirm ac INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID INNER JOIN subjects subj ON subj.subjectID=sr.subjectID INNER JOIN staffaccounts sa ON sa.staffID=sr.staffID LEFT JOIN subbatches sb ON sb.subbatchID=ac.subbatchID WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.attendanceDate BETWEEN '" . date('Y-m-d', strtotime($attendanceFromDate)) . "' AND '" . date('Y-m-d', strtotime($attendanceToDate)) . "'";
        if ($subbatchId) {
            $sql .= " AND ac.subbatchID IN (" . $subbatchId . ",0)";
        }
        if ($hour) {
            $sql .= " AND ac.hour='$hour'";
        }
        if ($sbsId) {
            $sql .= " AND ac.sbsID = '" . $sbsId . "'";
        }
        try {
            $staffDetails = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $staffDetails;
    }
    /**
     * Undocumented function
     *
     * @param [type] $batchId
     * @param [type] $semId
     * @param [type] $attendanceFromDate
     * @param [type] $attendanceToDate
     * @param [type] $hour
     * @param integer $subbatchId
     * @param [type] $sbsId
     * @return void
     */
    public function getAttendanceConfirmedDetailsForAGivenDateRange($batchId, $semId, $attendanceFromDate, $attendanceToDate, $hour = NULL, $subbatchId = 0, $sbsId = null)
    {
        $attendanceDateList = NULL;
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $attendanceFromDate = $this->realEscapeString($attendanceFromDate);
        $attendanceToDate = $this->realEscapeString($attendanceToDate);
        $hour = $this->realEscapeString($hour);
        $subbatchId = $this->realEscapeString($subbatchId);
        $sbsId = $this->realEscapeString($sbsId);
        if ($attendanceFromDate == $attendanceToDate) {
            $sql = "SELECT DISTINCT ac.attendanceDate FROM attendance_confirm ac WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.attendanceDate = '$attendanceFromDate";
        } else {
            $sql = "SELECT DISTINCT ac.attendanceDate FROM attendance_confirm ac WHERE ac.batchID='$batchId'  AND ac.semID='$semId' AND ac.attendanceDate BETWEEN '$attendanceFromDate' AND '$attendanceToDate'";
        }
        if ($subbatchId) {
            $sql .= " AND ac.subbatchID IN (" . $subbatchId . ",0)";
        }
        if ($hour) {
            $sql .= " AND ac.hour='$hour'";
        }
        if ($sbsId) {
            $sql .= " AND ac.sbsID = '" . $sbsId . "'";
        }
        try {
            $attendanceDateList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDateList;
    }
    /**
     * Undocumented function
     *
     * @param [type] $studentId
     * @param [type] $batchId
     * @param [type] $semId
     * @return void
     */
    public function getSubjectWiseStudentAttendanceWithAttendanceRulesConsidered($studentId, $batchId, $semId)
    {
        $attendanceRules = $this->getAttendanceRule($batchId, $semId);
        $studentDetails = StudentService::getInstance()->getStudentDetailsById($studentId);
        $fromDate = "";
        $toDate = "";
        $toDate = date('Y-m-d');
        if ($attendanceRules->dateOfjoining) {
            if (strtotime($studentDetails->studentJoindate) < strtotime($attendanceRules->classStartsFrom)) {
                $fromDate = $attendanceRules->classStartsFrom;
            } else {
                $fromDate = $studentDetails->studentJoindate;
            }
        } else {
            $fromDate = $attendanceRules->classStartsFrom;
        }
        if ($attendanceRules->classEndsDate && $attendanceRules->classEndsDate != '0000-00-00') {
            if (strtotime($toDate) > strtotime($attendanceRules->classEndsDate)) {
                $toDate = $attendanceRules->classEndsDate;
            }
        }
        return $this->getStudentAttendanceDetailsSubjectWise($batchId, $semId, $studentId, $fromDate, $toDate);
    }
    /**
     * Get athe attendance details of students for a subject in an attendance range
     * @param Integer $batchId
     * @param Integer $semId
     * @param Integer $subjectId
     * @param String $fromDate
     * @param String $toDate
     * @param Integer $subbatchId
     * @param String $sortByColumn
     * @return Object
     * @throws ProfessionalException
     * @author Vishnu M
     */
    public function getSubjectAttendanceInDateRange($batchId, $semId, $subjectId, $fromDate, $toDate, $subbatchId = NULL, $sortByColumn = 'rollNo')
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $fromDate = $this->realEscapeString($fromDate);
        $toDate = $this->realEscapeString($toDate);
        $subbatchId = $this->realEscapeString($subbatchId);
        $condition = null;
        try {
            $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($semId);
            $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($batchId, $semId);
            if ($subbatchId) {
                $condition .= " AND ( ac.subbatchID = 0 OR ac.subbatchID = '$subbatchId' ) AND sa.studentID IN (SELECT studentID FROM subbatch_student WHERE subbatchID = '$subbatchId') ";
            }
            if ($subjectId) {
                $condition .= " AND sbs.subjectID = '$subjectId";
            }
            $sql = "SELECT 
            sa.studentID,
            sa.studentAccount,
            sa.studentName,
            sa.studentEmail,
            sa.batchID,
            sa.deptID,
            sa.admissionNo,
            sa.rollNo,
            sa.regNo,
            ac.attendanceDate,
            ac.hour,
            (CASE
                WHEN attn.isAbsent = 1 THEN 'A'
                WHEN attn.isBlocked = 1 THEN 'A'
                WHEN attn.isAbsent = 0 THEN 'P'
                WHEN attn.isAbsent = 2 THEN 'DL'
            END) AS isAbsent,
            attn.staffID,
            CONCAT(ac.attendanceDate, ac.hour) AS attendanceId,
            ac.sbsID,
            ac.subbatchID
            FROM
                attendance_confirm ac
                    INNER JOIN
                studentaccount sa ON sa.batchID = ac.batchID
                    INNER JOIN
                sbs_relation sbs ON (sbs.sbsID = ac.sbsID
                    AND sbs.batchID = ac.batchID
                    AND sbs.semID = ac.semID)
                    LEFT JOIN
                attendance attn ON (sa.studentID = attn.studentID
                    AND ac.attendanceDate = attn.attendanceDate
                    AND ac.hour = attn.hour
                    AND sa.batchID = attn.batchID
                    AND sbs.semID = attn.semID)
                    INNER JOIN
                semesters joinedSem ON sa.joiningSemId = joinedSem.semID
            WHERE
                joinedSem.orderNo <= '$semDetails->orderNo'
                    AND ac.batchID = '$batchId'
                    AND ac.semID = '$semId'
                    AND ac.attendanceDate BETWEEN '$fromDate' AND '$toDate'
                    $condition
            ";
            if (!$isCurrentSem) {
                $unionSql = "SELECT sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour, (CASE WHEN attn.isAbsent = 1 THEN 'A' WHEN attn.isBlocked = 1 THEN 'A' WHEN attn.isAbsent = 0 THEN 'P' WHEN attn.isAbsent = 2 THEN 'DL' END ) AS isAbsent, attn.staffID, CONCAT(ac.attendanceDate, ac.hour) AS attendanceId, ac.sbsID, ac.subbatchID FROM attendance_confirm ac INNER JOIN sbs_relation sbs ON (sbs.sbsID = ac.sbsID AND sbs.batchID = ac.batchID AND sbs.semID = ac.semID) INNER JOIN failed_students fs on (fs.previousBatch = ac.batchID) left join semesters fsem on fsem.semID = fs.failedInSemester left join studentaccount sa on sa.studentID = fs.studentID left join attendance attn on sa.studentID = attn.studentID and ac.attendanceDate = attn.attendanceDate and ac.hour = attn.hour INNER JOIN semesters joinedSem on sa.joiningSemId = joinedSem.semID WHERE joinedSem.orderNo <= '$semDetails->orderNo' and ac.batchID = '$batchId' and ac.semID = '$semId' AND ac.attendanceDate between '$fromDate' AND '$toDate' AND fsem.orderNo > " . $semDetails->orderNo . " $condition";
                if($sortByColumn)
                {
                    $sql = "(" . $sql . ") UNION (" . $unionSql . ")  ORDER BY " . $sortByColumn . ", attendanceDate, hour";
                }
                else{
                    $sql = "(" . $sql . ") UNION (" . $unionSql . ")  ORDER BY attendanceDate, hour";
                }
            } else {
                if($sortByColumn)
                {
                    $sql .= " ORDER BY sa." . $sortByColumn . ", ac.attendanceDate, ac.hour";
                }
            }
            // error_log($sql);
            return $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_STUDENT_ATTENDANCE_DETAILS]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param $request
     * @return Object|null
     * @throws ProfessionalException
     */
    public function getStudentListForAllPseudoSubjectsInAnAttendanceHour($request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "SELECT GROUP_CONCAT( DISTINCT sbsID) as sbsIds FROM attendance WHERE attendanceDate = '$request->timetableDate' AND hour='$request->hourId' AND semID = '$request->semId' AND batchID = '$request->batchId'";
        try {
            $sbsIds = $this->executeQueryForObject($sql)->sbsIds;
        } catch (\Exception $th) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (empty($sbsIds)) {
            return null;
        }
        if (empty($request->sortBy)) {
            try {
                $request->sortBy = BatchService::getInstance()->getStudentSortByColumnOfABatch($request->batchId);
            } catch (\Exception $e) {
                $request->sortBy = 'rollNo';
            }
        }
        $sql = "SELECT 
        sta.studentID, sta.rollNo, sta.studentName, att.isAbsent, att.attendanceDate, att.semID,att.hour, bat.batchID as batchId, bat.batchName, pseudo_sub.pseudosubjectID, pseudo_sub.subjectName 
    FROM
        pseudosubjects_sbs pseudo_sbs
            INNER JOIN
            pseudosubjects pseudo_sub ON pseudo_sbs.sbsID IN ($sbsIds)
            AND pseudo_sub.pseudosubjectID = pseudo_sbs.pseudosubjectID
            INNER JOIN
        pseudosubjects_students pseudo_stud ON pseudo_stud.pseudosubjectID = pseudo_sub.pseudosubjectID
            AND pseudo_sub.pseudosubjectID = pseudo_sbs.pseudosubjectID
            INNER JOIN
        studentaccount sta ON sta.studentID = pseudo_stud.studentID
            INNER JOIN
        attendance att ON att.studentID = sta.studentID  AND att.hour = '$request->hourId'
            AND att.attendanceDate = '$request->timetableDate
            AND att.batchID <> '$request->batchId'
            INNER JOIN 
        batches bat ON bat.batchID = att.batchID";
        $sql .= " order by sta.$request->sortBy $request->sortOrder";
        try {
            $studentList = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_STUDENT_LIST_FOR_ALL_PSEUDO_SUBJECT_IN_AN_HOUR]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentList;
    }
    /**
     * @param CheckAttendanceConfirmedRequest $request
     * @return bool
     * @throws ProfessionalException
     */
    public function isAttendanceConfirmed(CheckAttendanceConfirmedRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "SELECT DISTINCT batchID FROM attendance_confirm WHERE batchID = $request->batchId
                AND semID = $request->semesterId  AND attendanceDate = '$request->attendanceDate'
                AND hour = $request->hourId AND subbatchID = $request->subBatchId";
        try {
            $batchId = $this->executeQueryForObject($sql)->batchID;
            if (!empty($batchId)) {
                return true;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return false;
    }
    /**
     * @param MarkAllAttendanceRequest $request
     * @throws ProfessionalException
     */
    public function markAllPresentOrAbsentByBatch(MarkAllAttendanceRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->batchId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_BATCH_ID, "Invalid batch given");
        }
        if (empty($request->attendanceDate)) {
            throw new ProfessionalException(ProfessionalException::INVALID_DATE, "Invalid attendance date given");
        }
        if (empty($request->sbsId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_DATE, "Invalid attendance date given");
        }
        if (empty($request->hour)) {
            throw new ProfessionalException("INVALID_HOUR", "Invalid hour given");
        }
        if (empty($request->semesterId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_SEMESTER_ID, "Invalid semester given");
        }
        $sql = "INSERT IGNORE INTO attendance (studentID, attendanceDate, hour, day, semID, batchID, isAbsent, staffID, 
                sbsID, csID, isBlocked, subbatchId, createdBy, createdDate, updatedBy, updatedDate) 
                (SELECT studentID,'$request->attendanceDate',$request->hour,'$request->day',$request->semesterId,
                       $request->batchId,$request->isAbsent,$request->staffId,$request->sbsId,0,0,$request->subBatchId,
                       $request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP() 
                FROM studentaccount  sa 
                INNER JOIN batches b on sa.batchID = b.batchID
                WHERE b.batchID = $request->batchId)";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param MarkAllAttendanceRequest $request
     * @throws ProfessionalException
     */
    public function markAllPresentOrAbsentBySubBatch(MarkAllAttendanceRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->subBatchId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_SUB_BATCH_ID, "Invalid sub-batch given");
        }
        if (empty($request->attendanceDate)) {
            throw new ProfessionalException(ProfessionalException::INVALID_DATE, "Invalid attendance date given");
        }
        if (empty($request->sbsId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_DATE, "Invalid attendance date given");
        }
        if (empty($request->hour)) {
            throw new ProfessionalException("INVALID_HOUR", "Invalid hour given");
        }
        if (empty($request->semesterId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_SEMESTER_ID, "Invalid semester given");
        }
        $sql = "INSERT IGNORE INTO attendance (studentID, attendanceDate, hour, day, semID, batchID, isAbsent, staffID, 
                sbsID, csID, isBlocked, subbatchId, createdBy, createdDate, updatedBy, updatedDate) 
                (SELECT studentID,'$request->attendanceDate',$request->hour,'$request->day',$request->semesterId,
                       $request->batchId,$request->isAbsent,$request->staffId,$request->sbsId,0,0,$request->subBatchId,
                       $request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,UTC_TIMESTAMP() 
                FROM subbatch_student  ss
                INNER JOIN subbatches sb on ss.subbatchID = sb.subbatchID
                WHERE sb.subbatchID = $request->subBatchId)";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * @param ConfirmAttendanceRequest $request
     * @throws ProfessionalException
     */
    public function confirmAttendance(ConfirmAttendanceRequest $request)
    {
        $request = $this->realEscapeObject($request);
        if (empty($request->batchId)) {
            throw new ProfessionalException(ProfessionalException::INVALID_BATCH_ID, "Invalid batch given");
        }
        if (empty($request->attendanceDate)) {
            throw new ProfessionalException(ProfessionalException::INVALID_DATE, "Invalid attendance date given");
        }
        $sql = "INSERT INTO attendance_confirm (batchID, subbatchID, semID, hour, attendanceDate, sbsID, csID, exam_id, 
                confirmedDate, attendanceMethod, staffID,remarks, createdBy, createdDate, updatedBy, updatedDate) 
                VALUES ($request->batchId,$request->subBatchId,$request->semesterId,$request->hourId,
                '$request->attendanceDate',$request->sbsId,'$request->csId','$request->exam_id','$request->confirmDate',
                        '$request->attendanceMethod', '$request->staffId','$request->remarks', $request->createdBy,UTC_TIMESTAMP(),$request->updatedBy,
                        UTC_TIMESTAMP)";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get attendance by studentId, date & hour
     * @param Integer $studentId
     * @param Integer $attendanceDate
     * @param Integer $hour
     * @return Object $attendance
     * @throws ProfessionalException
     * @author Vishnu M
     */
    public function  getAttendanceDetailsByStudentDateHour($studentId, $attendanceDate, $hour)
    {
        $attendance = null;
        $studentId = (int) $this->realEscapeString($studentId);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $hour = (int) $this->realEscapeString($hour);
        try {
            $sql = "SELECT studentId, attendanceDate, hour, day, semID, batchID, isAbsent, staffID, sbsID, csID,isBlocked, dlrId,createdDate FROM attendance WHERE studentID = '$studentId' AND attendanceDate = '$attendanceDate' AND hour = '$hour";
            $attendance = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendance;
    }
    /**
     * Get attendance by studentId, date & hour
     * @param Integer $studentId
     * @param Integer $attendanceDate
     * @return Object $attendance
     * @throws ProfessionalException
     * @author Vishnu M
     */
    public function  getAttendanceDetailsByStudentIdAttendanceDate($studentId, $attendanceDate, $isv4 = false, $sessionKeys = null)
    {
        $attendance = [];
        $studentId = (int) $this->realEscapeString($studentId);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        try {
            if(!$isv4)
            {
                $sql = "SELECT studentId, attendanceDate, hour, day, semID, batchID, isAbsent, staffID, sbsID, csID,isBlocked, dlrId FROM attendance WHERE studentID = '$studentId' AND attendanceDate = '$attendanceDate' ORDER BY hour ASC ";
                $attendance = $this->executeQueryForList($sql);
            }
            else{
                $sql = "SELECT
                            va.student_id as studentId ,
                            va.attendance_date as attendanceDate,
                            vamu.marked_hour as hour ,
                            va.is_absent as isAbsent ,
                            caps.properties->>'$.subjectTypeId' as subjectType,
                            s.id as subjectID,
                            s.name as subjectName,
                            s.description as subjectDescription
                        from
                            v4_attendance va
                        INNER JOIN v4_attendance_marked_user vamu on
                            vamu.id = va.v4_attendance_marked_user_table_id
                            INNER JOIN cluster c on c.id = va.cluster_id 
                            INNER JOIN cluster_groups_relations cgr on cgr.cluster_id = c.id 
                            INNER JOIN `groups` g on g.id = cgr.groups_id
                            INNER JOIN cm_academic_paper_subjects caps on caps.id = g.paperSubjectId 
                            INNER JOIN v4_ams_subject s ON s.id = caps.ams_subject_id
                        WHERE
                            va.student_id = '$studentId'
                            and va.attendance_date = '$attendanceDate'
                            and vamu.marked_hour in ($sessionKeys)
                        ORDER BY vamu.marked_hour ASC ";
                            
                $attendance = $this->executeQueryForList($sql);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendance;
    }
    public function deactivateAttendanceRule($rule)
    {
        $sql = "update attendance_rules set isActive = '0' where batchID = $rule->batchId and semId = $rule->semId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function activateAttendanceRule($rule)
    {
        $sql = "update attendance_rules set isActive = '1' where batchID = $rule->batchId and semId = $rule->semId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function deleteAttendanceRuleByBatchIDAndSemID($batchID, $semID)
    {
        $sql = "delete from attendance_rules where batchID = '$batchID' and semID = '$semID'";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get attendance percentage by subject catagory id and student ID
     * @param int $studentID
     * @param int $subjectCatID
     * @param unknown $attendanePercentage
     * @throws AutonomousException
     * @return object|NULL|\com\linways\base\util\$objectList[]
     */
    public function getAttendancePercentageBySubjectIDAndStudentID($studentID, $subjectID, $isv4 = false, $holidates = null)
    {
        $studentID = $this->realEscapeString($studentID);
        $subjectID = $this->realEscapeString($subjectID);
        try {
            if(!$isv4)
            {
                $sql = "select sa.batchID,bat.semID from studentaccount sa inner join batches bat on sa.batchID = bat.batchID where sa.studentID ='" . $studentID . "';";
                $studentDetail = $this->executeQueryForObject($sql);
                if ($studentDetail) {
                    $attendanceRule = AttendanceService::getInstance()->getAttendanceRule($studentDetail->batchID, $studentDetail->semID);
                    if (!empty($attendanceRule)) {
                        if ($attendanceRule->classStartsFrom && $attendanceRule->classEnds) {
                            $dateCondition = " and attendanceDate between '" . $attendanceRule->classStartsFrom . "' and '" . $attendanceRule->classEnds . "' ";
                        } elseif ($attendanceRule->classStartsFrom) {
                            $dateCondition = " and attendanceDate >= '" . $attendanceRule->classStartsFrom . "' ";
                        } elseif ($attendanceRule->classEnds) {
                            $dateCondition = " and attendanceDate <= '" . $attendanceRule->classEnds . "' ";
                        }
                    }
                    $sql = "SELECT
                    (COUNT(CASE WHEN  att.isAbsent=0 OR att.isAbsent=2 THEN 1 END)/COUNT(att.studentID)) * 100 AS attPercent,(COUNT(CASE WHEN att.isAbsent=0 OR att.isAbsent=2 THEN 1 END))AS atthour,COUNT(att.studentID) as totalhour
                    FROM attendance att
                    inner join sbs_relation sbs on  att.sbsID = sbs.sbsID
                    inner join subjects sub on sbs.subjectID = sub.subjectID
                    WHERE att.studentID = '" . $studentID . "' AND att.semID= '" . $studentDetail->semID . "' and att.batchID = '" . $studentDetail->batchID . "'
                    and sub.subjectID ='" . $subjectID . "'$dateCondition;";
                    $response = $this->executeQueryForObject($sql);
                    return $response;
                } else {
                    return false;
                }
                
            }
            else{
                // for v4
                $cond = "";
                if($holidates)
                {
                    if(count($holidates) > 0)
                    {
                        $cond = " AND va.attendance_date NOT IN (".implode(",",$holidates);
                    }
                }
                $sql = "SELECT
                concat(IFNULL(s.name,''),' ( ' ,IFNULL(s.code,''),' )') as subjectName,
                caps.id as academicPaperId,
                COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time) AS totalAttendance,
                COUNT(DISTINCT CASE WHEN va.is_absent = 0 OR va.grant_leave IS NOT NULL THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS totalPresent,
                COUNT(DISTINCT CASE WHEN va.is_absent = 0 AND va.grant_leave IS  NULL THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS totalPresentMarkHour,
                COUNT(DISTINCT CASE WHEN va.grant_leave IS NOT NULL THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS totalDutyleave,
                ROUND(IFNULL((COUNT(DISTINCT CASE WHEN va.is_absent = 0 AND va.grant_leave IS  NULL THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) / COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time))*100,0),2) AS attendancePercentagewithoutDutyLeave,
                ROUND(IFNULL((COUNT(DISTINCT CASE WHEN va.is_absent = 0 OR va.grant_leave IS NOT NULL THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) / COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time))*100,0),2) AS attendancePercentage
              FROM
                cluster c
              INNER JOIN cluster_groups_relations cg ON
                cg.cluster_id = c.id
              INNER JOIN `groups` sg ON
                sg.id = cg.groups_id
                INNER JOIN groups_relations gr ON
                  sg.id = gr.child_groups_id
              INNER JOIN `groups` bg ON
                  bg.id = gr.parent_groups_id
              INNER JOIN cm_academic_paper_subjects caps ON
                caps.id = sg.paperSubjectId
              INNER JOIN v4_ams_subject s ON
                s.id = caps.ams_subject_id
              INNER JOIN group_members gm ON
                gm.groups_id = sg.id
              INNER JOIN student_program_account spa ON
                spa.id = gm.student_id AND bg.id = spa.current_batch_id
              INNER JOIN studentaccount sa ON
                sa.studentID = spa.student_id
              LEFT JOIN v4_attendance_marked_user vamu ON
                vamu.cluster_id = c.id
              LEFT join v4_timetable vt on vamu.time_table_id = vt.id and vt.suspended = '0'
              LEFT JOIN v4_attendance va ON
                va.v4_attendance_marked_user_table_id = vamu.id
                and va.student_id = sa.studentID
              where
                1 = 1  and gm.academic_status in ('COMPLETED','ACTIVE','REMOVED')    
                and sa.studentID = '$studentID'
                and s.id = '$subjectID'
                $cond";
                $attendance = $this->executeQueryForObject($sql);
                $attendance->attPercent = (float)$attendance->attendancePercentage;
                return $attendance;
            }
        } catch (\Exception $e) {
            throw new AutonomousException($e->getCode(), $e->getMessage());
        }
    }
    public function updateStudentAttandanceDLWithStudentID($studentID, $attandanceDate, $hour = null)
    {
        $studentID = $this->realEscapeString($studentID);
        $attandanceDate = $this->realEscapeString($attandanceDate);
        $hour = $this->realEscapeString($hour);
        $cond = "";
        $condHour = "";
        if ($hour) {
            $condHour = " AND att.hour='" . $hour . "' ";
        }
        try {
            if ($studentID && $attandanceDate) {
                $sql = "
                UPDATE attendance att
                    INNER JOIN student_leave_application sla ON sla.student_Id = att.studentID  AND find_in_set(att.hour,sla.session_key)
                    AND att.attendanceDate BETWEEN sla.start_date AND sla.end_date
                    INNER JOIN student_leave_type slt on slt.id = sla.leave_type_Id and slt.isDL = 1 and slt.isActive=1
                SET isAbsent = 2
                WHERE att.studentID ='" . $studentID . "' " . $condHour . " AND att.attendanceDate = '" . $attandanceDate . "' AND sla.status = 'APPROVED';";
                $this->executeQuery($sql);
            }
        } catch (Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function addAttndanceFromTemp($request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "INSERT INTO attendance (studentID, attendanceDate, hour, semID, batchID, isAbsent, staffID, sbsID, subbatchId, createdBy, createdDate, updatedBy, updatedDate) select studentID, attendanceDate, hour, semID, batchID, isAbsent, " . $request->staffID . ", " . $request->sbsID . "$request->subbatchID" . $request->createdBy . ", utc_timestamp(), " . $request->updatedBy . ", utc_timestamp() from attendance_temporary where batchID=\"" . $request->batchID . "\" and semID=\"" . $request->semID . "\" and hour=\"" . $request->hour . "\" and attendanceDate=\"" . $request->attendanceDate . "\" and subbatchID = \"" . $request->subbatchID . "\"";
        try {
            $this->executeQuery($sql);
        } catch (Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * check attendance marked for all batch or subbatch
     * @param Attendance $attendance
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function isAttendanceMarkedForAllStudent($attendance)
    {
        $attendance = $this->realEscapeObject($attendance);
        $studentDetails = NULL;
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($attendance->batchID, $attendance->semID);
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($attendance->semID);
        if ($attendance->subbatchId) {
            if ($isCurrentSem) {
                $sql = "select sta.studentID, sta.studentName, sta.rollNo, sta.regNo, sta.admissionNo, at.isAbsent, at.sbsID as markedSbsId, if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sta.myImage, sta.studentGender from studentaccount sta INNER JOIN  subbatches subb ON subb.batchID=sta.batchID INNER JOIN  subbatch_student substu ON sta.studentID=substu.studentID AND substu.subbatchID=subb.subbatchID LEFT JOIN attendance at ON at.studentID=sta.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID inner join semesters joinSem on joinSem.semID = sta.joiningSemId inner join batches ba on ba.batchID = sta.batchID inner join semesters sem on sem.semID = ba.semID  where subb.semID=$attendance->semID AND substu.subbatchID=$attendance->subbatchId and joinSem.orderNo <= sem.orderNo AND at.studentID is null";
            } else {
                $sql = "select sta.studentID, sta.studentName, sta.rollNo, sta.regNo, sta.admissionNo, at.isAbsent, at.sbsID as markedSbsId, if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sta.myImage, sta.studentGender from studentaccount sta INNER JOIN  subbatches subb ON subb.batchID=sta.batchID INNER JOIN subbatch_student substu ON sta.studentID=substu.studentID AND substu.subbatchID=subb.subbatchID LEFT JOIN attendance at ON at.studentID=sta.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID where subb.semID=$attendance->semID AND substu.subbatchID=$attendance->subbatchId AND sta.studentID in(select sa.studentID from studentaccount sa  inner join semesters joinSem on joinSem.semID = sa.joiningSemId inner join batches ba on ba.batchID = sa.batchID inner join semesters sem on sem.semID = ba.semID where ba.batchID = $attendance->batchID and joinSem.orderNo <= sem.orderNo union select sa.studentID from failed_students fs inner join studentaccount sa on sa.studentID = fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo) AND at.studentID is null";
            }
        } else {
            if ($isCurrentSem) {
                $sql = "select sa.studentID, sa.studentName, sa.rollNo, sa.regNo, sa.admissionNo, at.isAbsent, at.sbsID as markedSbsId,  if(sr.batchID !=$attendance->batchID,'1','0') as isMarkedOtherBatch, sa.myImage, sa.studentGender from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on joinedSem.semID = sa.joiningSemId LEFT JOIN attendance at ON at.studentID=sa.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' AND at.hour=$attendance->hour left join sbs_relation sr ON sr.sbsID=at.sbsID where sa.batchID=$attendance->batchID and joinedSem.orderNo <= sem.orderNo AND at.studentID is null";
            } else {
                $sql = "select studentID, studentName, rollNo, regNo, admissionNo, myImage, studentGender from (select studentID, studentName, rollNo, regNo, admissionNo, sa.myImage, sa.studentGender from studentaccount sa inner join batches ba on sa.batchID = ba.batchID inner join semesters sem on sem.semID = ba.semID inner join semesters joinedSem on joinedSem.semID = sa.joiningSemId  where ba.batchID = $attendance->batchID and joinedSem.orderNo <= $semDetails->orderNo union select fs.studentID, studentName, rollNo, regNo, admissionNo from failed_students fs inner join studentaccount sa on sa.studentID = fs.studentID inner join semesters fsem on fsem.semID = fs.failedInSemester inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID where previousBatch = $attendance->batchID and fsem.orderNo > $semDetails->orderNo and joinedSem.orderNo <= $semDetails->orderNo) as studentID where studentID not in (select t1.studentID from  studentaccount t1, attendance t3  where t1.studentID=t3.studentID and t3.batchID=$attendance->batchID and t3.hour=$attendance->hour and t3.attendanceDate='" . date('Y-m-d', strtotime($attendance->attendanceDate)) . "' and t3.semID=$attendance->semID);";
            }
        }
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
            }
            if (count($studentDetails) > 0) {
                return false;
            } else {
                return true;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * check attendance marked or not for a hour
     * @param int $psId
     * @param int $hour
     * @param string $attendanceDate
     * @return boolean
     * @throws ProfessionalException
     */
    public function isAttendanceMarkedForPseudoSubject($psId, $hour, $attendanceDate)
    {
        $psId = $this->realEscapeString($psId);
        $hour = $this->realEscapeString($hour);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $studentDetails = NULL;
        $sql = "select sta.studentID, sta.studentName, sta.rollNo, sta.regNo, sta.admissionNo, at.isAbsent, at.sbsID as markedSbsId, if(sr.batchID !=sta.batchID,'1','0') as isMarkedOtherBatch, sta.myImage, sta.studentGender from studentaccount sta INNER JOIN  subbatches subb ON subb.batchID=sta.batchID INNER JOIN  subbatch_student substu ON sta.studentID=substu.studentID AND substu.subbatchID=subb.subbatchID LEFT JOIN attendance at ON at.studentID=sta.studentID AND at.attendanceDate='" . date('Y-m-d', strtotime($attendanceDate)) . "' AND at.hour=$hour left join sbs_relation sr ON sr.sbsID=at.sbsID inner join semesters joinSem on joinSem.semID = sta.joiningSemId inner join batches ba on ba.batchID = sta.batchID inner join semesters sem on sem.semID = ba.semID  where subb.psID=$psId and joinSem.orderNo <= sem.orderNo AND at.studentID is null";
        try {
            $studentDetails = $this->executeQueryForList($sql);
            foreach($studentDetails as $idx => $student){
                $studentDetails[$idx]->myImage = StudentService::getInstance()->getStudentProfilePic($student->studentID)->docpath;
            }
            if (count($studentDetails) > 0) {
                return false;
            } else {
                return true;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get student attendance percentage semester wise of student
     * @param int $studentId
     * @param int $semId
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getStudentAttendancePercentageSemesterwise($studentId, $semId = null)
    {
        $studentId = $this->realEscapeString($studentId);
        $semId = $this->realEscapeString($semId);
        $sql = "select att.semID,(count(case when isAbsent = 0 then 1 end )/ count(att.studentID)) * 100 as attendancePercent from attendance att where att.studentID = '$studentId'";
        if (!empty($semId)) {
            $sql .= " AND att.semID='$semId";
        }
        $sql .= " GROUP BY att.semID ";
        try {
            if (!empty($semId)) {
                $attendancePercent = $this->executeQueryForObject($sql);
            } else {
                $attendancePercent = $this->executeQueryForList($sql);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendancePercent;
    }
    
    public function addAttendanceAfterSemesterRegistrationByStudentId($studentId, $subbatch=false)
    {
        $studentId = $this->realEscapeString($studentId);
        $semId = BatchService::getInstance()->getBatchDetailsByStudentId($studentId)->semID;
        $prevSemId = SemesterService::getInstance()->getPreviousSemId($semId);
        if($subbatch==true)
        {
            $sql ="INSERT IGNORE INTO attendance (studentID, attendanceDate, hour, semID, batchID, isAbsent, staffID, sbsID, isBlocked, subbatchId, createdBy, createdDate, updatedBy, updatedDate) select $studentId, ac.attendanceDate, ac.hour, ac.semID, ac.batchID, 1, ac.staffID, ac.sbsID, 1, ac.subbatchID,1, utc_timestamp(),1, utc_timestamp() from attendance_confirm ac INNER JOIN batches bt ON bt.batchID=ac.batchID AND ac.semID=bt.semID inner join studentaccount sa ON sa.batchID=bt.batchID INNER JOIN subbatch_student ss ON ss.studentID=sa.studentID AND ac.subbatchID=ss.subbatchID INNER JOIN semRegistration sr ON sr.batchId=bt.batchID INNER JOIN semRegistrationStudentDetails srs ON srs.semRegistrationId=sr.id and srs.studentId = sa.studentID where sa.studentID=$studentId AND srs.name='confirmedByHod' AND sr.semId=$prevSemId";
        }
        else
        {
            $sql="INSERT IGNORE INTO attendance (studentID, attendanceDate, hour, semID, batchID, isAbsent, staffID, sbsID, isBlocked, subbatchId, createdBy, createdDate, updatedBy, updatedDate) select $studentId, ac.attendanceDate, ac.hour, ac.semID, ac.batchID, 1, ac.staffID, ac.sbsID, 1, ac.subbatchID,1, utc_timestamp(),1, utc_timestamp() from attendance_confirm ac INNER JOIN batches bt ON bt.batchID=ac.batchID AND ac.semID=bt.semID inner join studentaccount sa ON sa.batchID=bt.batchID INNER JOIN semRegistration sr ON sr.batchId=bt.batchID INNER JOIN semRegistrationStudentDetails srs ON srs.semRegistrationId=sr.id and srs.studentId = sa.studentID where sa.studentID=$studentId AND srs.name='confirmedByHod' AND sr.semId=$prevSemId";
        }
        
        $date_sql ="select sr.classStartDate, srs.createdDate from semRegistration sr inner join batches bth ON bth.batchID=sr.batchId INNER JOIN semRegistrationStudentDetails srs ON srs.semRegistrationId=sr.id WHERE srs.studentId=$studentId AND srs.name='confirmedByHod' AND sr.semId=$prevSemId";
        $dateData = $this->executeQueryForObject($date_sql);
        $dateList = CommonUtil::getDatesBetweenTwoRange($dateData->classStartDate, date('Y-m-d', strtotime($dateData->createdDate)));
        $hourList = $this->getAttendanceHours();
        $hours = implode(',', $hourList);
        $blockAttendanceList=[];
        foreach ($dateList as $date)
        {
            $blockAttendance = new BlockAttendance();
            $blockAttendance->date=$date->date;
            $blockAttendance->hours=$hours;
            $blockAttendance->studentId=$studentId;
            
            $blockAttendanceList[]=$blockAttendance;
        }
        try {
            if(!empty($blockAttendanceList))
            {
                $this->blockStudentAttendance($blockAttendanceList);
            }
            return $this->executeQueryForObject($sql);
            
        } catch (\Exception $e) {
            
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    
    
    public function removeAttendanceAfterSubbatchRemoveByStudentId($studentId)
    {
        $studentId = $this->realEscapeString($studentId);
            $sql ="DELETE ac.* FROM attendance ac inner join studentaccount sa ON sa.batchID=ac.batchID INNER JOIN batches bt ON bt.batchID=ac.batchID AND ac.semID=bt.semID INNER JOIN subbatch_student ss ON ss.studentID=sa.studentID AND ac.subbatchID=ss.subbatchID INNER JOIN semRegistration sr ON sr.batchId=bt.batchID AND sr.semId=bt.semID INNER JOIN semRegistrationStudentDetails srs ON srs.semRegistrationId=sr.id where attendanceDate between sr.classStartDate AND srs.createdDate AND sa.studentID=$studentId AND srs.name='confirmedByHod'";
        
        try {
            
            return $this->executeQueryForObject($sql);
            
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getCurrentAttendanceRule($batchID = NULL ,$semID = NULL)
    {
        $condition = $batchID && $semID ? " where b.batchID = $batchID and b.semID = ".$semID : "" ;
        $sql = "SELECT ar.classStartsFrom as classStartsFrom,
                        ar.classEnds as classEnds 
                        from batches b
                        inner join attendance_rules ar on ar.batchID = b.batchID 
                        and ar.semID = b.semID 
                        and b.batchHide = 0 
                        and b.is_admission = 0 
                        and b.isPassOut = 0 ".$condition." order by ar.classStartsFrom desc";
        try 
        {
            return $this->executeQueryForObject($sql);
        } 
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    
    public function academicAuditReport($batchList, $semId)
    {
        $sql = "select sr.batchID, bt.patterncourseID, sr.subjectID, pd.patterncourseCode, sa.staffID, sa.staffName, sb.subjectName,  es.credit, JSON_EXTRACT(`extraSettings` , '$.auditReportConstant') as auditReportConstant, count(ac.id) as hourTaken from attendance_confirm ac INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID INNER JOIN batches bt ON bt.batchID=sr.batchID INNER JOIN staffaccounts sa ON sa.staffID=ac.staffID INNER JOIN subjects sb ON sb.subjectID=sr.subjectID INNER JOIN subject_category sc ON sc.subjectcatID=sb.subjectcatID INNER JOIN pattern_deptcourses pd ON pd.patterncourseID=bt.patterncourseID LEFT JOIN exam_subjectcredit es ON es.batchID=bt.batchID AND es.semID=sr.semID AND es.subjectID=sr.subjectID 
        WHERE sc.code IN ('THEORY','LANGUAGE','OPEN ELECTIVE','PRACTICAL') AND bt.batchID IN(".implode(', ', $batchList).") AND sr.semID='$semId' group by ac.staffID, sr.subjectID, bt.patterncourseID";
        try
        {
            return $this->executeQueryForList($sql,$this->mapper[AttendanceServiceMapper::GET_AUDIT_REPORT]);
        }
        catch (\Exception $e) {
            
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    
    public function confirmHourAttendance($request)
    {
        
        $attendance = new Attendance();
        $attendance->attendanceDate=$request->attendanceDate;
        $attendance->hour=$request->hour;
        $attendance->batchID=$request->batchID;
        $attendance->semID=$request->semID;
        $attendance->subbatchId=$request->subBatchId;
        
        
        
        $attendanceRequest = new \stdClass();
        $attendanceRequest->staffID=$request->staffId;
        $attendanceRequest->sbsID=$request->sbsId;
        $attendanceRequest->subbatchID=$request->subBatchId;
        $attendanceRequest->batchID=$request->batchID;
        $attendanceRequest->semID=$request->semID;
        $attendanceRequest->hour=$request->hour;
        $attendanceRequest->attendanceDate=$request->attendanceDate;
        $attendanceRequest->createdBy=$request->createdBy;
        $attendanceRequest->updatedBy=$request->updatedBy;
        
        $confirmAttendanceRequest = new ConfirmAttendanceRequest();
        $confirmAttendanceRequest->attendanceDate=$request->attendanceDate;
        $confirmAttendanceRequest->batchId=$request->batchID;
        $confirmAttendanceRequest->confirmDate=date('Y-m-d');
        $confirmAttendanceRequest->subBatchId=$request->subBatchId;
        $confirmAttendanceRequest->hourId=$request->hour;
        $confirmAttendanceRequest->csId=0;
        $confirmAttendanceRequest->exam_id='';
        $confirmAttendanceRequest->sbsId=$request->sbsId;
        $confirmAttendanceRequest->semesterId=$request->semID;
        $confirmAttendanceRequest->attendanceMethod=$request->attendanceMethod;
        $confirmAttendanceRequest->staffId=$request->staffId;
        $confirmAttendanceRequest->remarks = $request->remarks; 
        $confirmAttendanceRequest->createdBy=$request->createdBy;
        $confirmAttendanceRequest->updatedBy=$request->updatedBy;
        
        try {
                $this->beginTransaction();
                $this->addAttndanceFromTemp($attendanceRequest);
                $this->confirmAttendance($confirmAttendanceRequest);
                $this->commit();
                $this->blockAttendance($request->attendanceDate, $request->hour, $request->batchID, $request->semID);
                $attendance->sbsID=$request->sbsId;
                $this->deleteAttendanceConfirmTemporary($attendance);
                $attendance->sbsID=null;
                $this->deleteAttendanceTemporary($attendance);
        } catch (\Exception $e) {
            $this->rollBack();
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
}
     /**
     * Get student attendance percentage for an exam registration.
     * @param int $studentId
     * @param int $examRegId
     * @return object|NULL
     * @throws ProfessionalException
     */
    public function getStudentAttendancePercentageDetails($studentId, $examRegId)
    {
        global $ATTENDANCE_HOURS;
        $studentId = $this->realEscapeString($studentId);
        $examRegId = $this->realEscapeString($examRegId);
        if ( empty ( $studentId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Student can not be null");
        }
        if ( empty ( $examRegId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Exam registration can not be null");
        }
        $sqlGetAttendanceDetails = "SELECT
            er.attClosingDate,
            er.examregName AS examRegName,
            er.min_att_percent AS minAttPercentage,
            erb.semID AS semId,
            erb.batchID AS batchId,
            erb.attClosingDate AS batchAttClossingDate,
            sa.studentJoindate
        FROM
            exam_registration_batches erb
        INNER JOIN studentaccount sa ON
            sa.batchID = erb.batchID
        INNER JOIN exam_registration er ON
            er.examregID = erb.examregID
        WHERE
            sa.studentID = $studentId
            AND erb.examregID = $examRegId;";
        try {
            // get attendance details for the batch, sem, and exam registration
            $attendanceDetail = $this->executeQueryForObject($sqlGetAttendanceDetails);
            $batchId = $attendanceDetail->batchId;
            $semId = $attendanceDetail->semId;
            $joinDate = $attendanceDetail->studentJoindate;
            $attClosingDate = $attendanceDetail->batchAttClossingDate;
            // Attendance Rule
            $attendanceRule = $this->getAttendanceRule($batchId, $semId);
            $morninghours = $attendanceRule->morninghours;
            $isAttendancePercentageCalculateFromJoingDate = $attendanceRule->dateOfjoining;
            $classStartsFrom = $attendanceRule->classStartsFrom;
            $classEnds = $attendanceRule->classEnds;
            $attendanceDetail->attendanceRule = $attendanceRule;
            // attendance dates and attendance details
            if ($isAttendancePercentageCalculateFromJoingDate && (strtotime($joinDate) >= strtotime($classStartsFrom)) && (strtotime($joinDate) <= strtotime($attClosingDate))) {
                $attendanceDates = $this->getAttendanceDates($batchId, $semId, $joinDate, $attClosingDate);
                $attendances = $this->getAttendanceDataOfStudent($batchId, $semId, $studentId, $joinDate, $attClosingDate);
            }
            else{
                $attendanceDates = $this->getAttendanceDates($batchId, $semId, $classStartsFrom, $attClosingDate);
                $attendances = $this->getAttendanceDataOfStudent($batchId, $semId, $studentId, $classStartsFrom, $attClosingDate);
            }
            // total attendace marked days for the batch in sem
            $totalAttandaceDays = count($attendanceDates); 
            // total attendace marked hours for the batch in sem
            $totalAttandaceHours = array_sum(array_column($attendanceDates, 'totalHours')); 
            $totalPresentDays = 0;
            $totalHalfDays = 0;
            $totalAbsentHours = 0;
            foreach ($attendanceDates as $attendanceDate) {
                $date = $attendanceDate->attendanceDate;
                $totalDayAbsentHours = 0;
                $morningPresent = true;
                $afterNoonPresent = true;
                for ($hour=1; $hour <= $ATTENDANCE_HOURS; $hour++) { 
                    $isAbsent = $attendances[$date]->hour[$hour]->isAbsent == "1"? true : false;
                    // set the isAbsent value as boolean value
                    $attendances[$date]->hour[$hour]->isAbsent = $isAbsent;
                    // check present status of morning and after noon sessions
                    if ($hour <= $morninghours && $isAbsent) {
                        $morningPresent = false;
                        $totalDayAbsentHours++;
                    }
                    else if ($isAbsent){
                        $afterNoonPresent = false;
                        $totalDayAbsentHours++;
                    }
                }
                $totalAbsentHours += $totalDayAbsentHours;
                $totalPresentDays += $morningPresent ? 0.5 : 0;
                $totalPresentDays += $afterNoonPresent ? 0.5 : 0;
                if (($morningPresent && !$afterNoonPresent) || (!$morningPresent && $afterNoonPresent)) {
                    $totalHalfDays++;
                }
                $attendances[$date]->morningPresent = $morningPresent;
                $attendances[$date]->afterNoonPresent = $afterNoonPresent;
                $attendances[$date]->totalDayAbsentHours = $totalDayAbsentHours;
                $attendances[$date]->isAbsent = !($morningPresent && $afterNoonPresent);
            }
            // hour-wise attendance %
            $attendanceDetail->totalAbsentHours = $totalAbsentHours;
            $attendanceDetail->totalAttandaceHours = $totalAttandaceHours;
            $attendanceDetail->totalAttandaceHourPercentage = $totalAttandaceHours ? (($totalAttandaceHours -  $totalAbsentHours) / $totalAttandaceHours) * 100 : 0;
            
            // day-wise attendance %
            $attendanceDetail->attendance = $attendances;
            $attendanceDetail->totalHalfDays = $totalHalfDays;
            $attendanceDetail->totalPresentDays = $totalPresentDays;
            $attendanceDetail->totalAttandaceDays = $totalAttandaceDays;
            $attendanceDetail->attendancePercentage = $totalAttandaceDays ? ($totalPresentDays / $totalAttandaceDays) * 100 : 0;
            $attendanceDetail->haveMinAttendance = $attendanceDetail->attendancePercentage >= $attendanceDetail->minAttPercentage;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $attendanceDetail;
    }
    public function getAttendanceDates($batchId, $semId, $startDate = null, $endDate = null)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        if ( empty ( $batchId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Batch can not be null");
        }
        if ( empty ( $semId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Sem can not be null");
        }
        $sqlConditions = "";
        
        if($startDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(attendanceDate) >= UNIX_TIMESTAMP('$startDate') ";
        }
        if($endDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(attendanceDate) <= UNIX_TIMESTAMP('$endDate') ";
        }
        $sql = "SELECT
            DISTINCT(attendanceDate),
            `hour`
        FROM
            attendance
        WHERE
            semID = $semId
            AND batchID = $batchId
            $sqlConditions 
        ORDER BY
            attendanceDate";
        try 
        {
            $attendanceDates = $this->executeQueryForList($sql);
            foreach ($attendanceDates as $attendanceDate) {
                $allAttendanceDates[$attendanceDate->attendanceDate]->attendanceDate = $attendanceDate->attendanceDate;
                $allAttendanceDates[$attendanceDate->attendanceDate]->hours[$attendanceDate->hour] = $attendanceDate->hour;
                $allAttendanceDates[$attendanceDate->attendanceDate]->totalHours++;
            }
        } 
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $allAttendanceDates;
    }
    public function getAttendanceDataOfStudent($batchId, $semId, $studentId, $startDate = null, $endDate = null, $considerDutyLeave = false)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $considerDutyLeave = $this->realEscapeString($considerDutyLeave);
        if ( empty ( $batchId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Batch can not be null");
        }
        if ( empty ( $semId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Sem can not be null");
        }
        if ( empty ( $studentId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Student can not be null");
        }
        $sqlConditions = "";
        $sqlDutyLeaveConditions = "";
        
        if($startDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(attendanceDate) >= UNIX_TIMESTAMP('$startDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.start_date) >= UNIX_TIMESTAMP('$startDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.end_date) >= UNIX_TIMESTAMP('$startDate') ";
        }
        if($endDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(attendanceDate) <= UNIX_TIMESTAMP('$endDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.start_date) <= UNIX_TIMESTAMP('$endDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.end_date) <= UNIX_TIMESTAMP('$endDate') ";
        }
        $sql = "SELECT
            attendanceDate,
            `hour`,
            `day`,
            isAbsent,
            staffID,
            sbsID,
            csID,
            isBlocked,
            subbatchId,
            dlrId
        FROM
            attendance
        WHERE
            studentID = $studentId
            AND batchID = $batchId
            AND semID = $semId
            $sqlConditions ";
        $sqlDutyLeave = "SELECT DISTINCT a.attendanceDate,
            sla.id,
            sla.leave_type_Id AS leaveTypeId,
            sla.session_key AS sessionKey,
            sla.start_date AS startDate,
            sla.end_date AS endDate,
            sla.applied_date AS appliedDate,
            sla.noof_days AS noOfDays,
            sla.description,
            sla.reason,
            sla.status,
            sla.lin_resources_id AS linResourceId,
            sla.userType,
            sla.workflowInstanceId,
            sla.dlrId,
            slt.id,
            slt.code,
            slt.name,
            slt.description,
            slt.isDL
        FROM
            student_leave_application sla
        INNER JOIN student_leave_type slt ON
            slt.id = sla.leave_type_Id and slt.isActive=1
        INNER JOIN attendance a
            ON sla.student_Id = a.studentID
            AND a.attendanceDate BETWEEN sla.start_date AND sla.end_date
        WHERE
            sla.student_Id = $studentId
            AND sla.status = 'APPROVED'
            $sqlDutyLeaveConditions ";
        try 
        {
            $attendanceDetails = $this->executeQueryForList($sql);
            $dutyLeaveDetails = $this->executeQueryForList($sql);
            
            foreach ($attendanceDetails as $attendance) {
                $sessionKeyFound = false;
                $studentAttendance[$attendance->attendanceDate]->date = $attendance->attendanceDate;
                $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour] = $attendance;
                $dutyLeaveArrayKey = array_search($attendance->attendanceDate, array_column($dutyLeaveDetails, 'attendanceDate'));
                $sessionKeys = json_decode("[".$dutyLeaveDetails[$dutyLeaveArrayKey]->sessionKey."]");
                if (!empty($sessionKeys)){
                    $sessionKeyFound = in_array($attendance->hour, $sessionKeys);
                }
                if ($dutyLeaveArrayKey !== false && $sessionKeyFound) {
                    $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour]->dutyLeave = $dutyLeaveDetails[$dutyLeaveArrayKey];
                    if ($considerDutyLeave) {
                        $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour]->isAbsent = false;
                    }
                }
                else{
                    $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour]->dutyLeave = null;
                }
            }
        } 
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentAttendance;
    }
    public function getStudentsAttendanceBySbsId($request)
    {
        try
        {
            $includeFailed = $request->includeFailed?$request->includeFailed:false;
            if($request->subjectType == "pseudoSubjects")
            {
                $sql_attendance = "SELECT std.studentID,std.rollNo, std.studentName,std.studentJoindate, (COUNT(CASE WHEN (att.isAbsent = 0) THEN 1 END) / COUNT(att.sbsID)) * 100 AS percentage, bat.batchName, sem.semName,count(distinct att.attendanceDate) as noOfDates
                    from pseudosubjects ps
                    inner join pseudosubjects_sbs psbs on ps.pseudosubjectID = psbs.pseudosubjectID
                    inner join sbs_relation sbs on psbs.sbsID = sbs.sbsID
                    inner join pseudosubjects_students pstd on pstd.pseudosubjectID = ps.pseudosubjectID
                    inner join studentaccount std on std.studentID = pstd.studentID and std.batchID = sbs.batchID 
                    inner join batches bat on bat.batchID = sbs.batchID 
                    inner join semesters sem on sem.semID = sbs.semID
                    left join attendance att on att.studentID = std.studentID and att.batchID = sbs.batchID and att.semID = sbs.semID and att.sbsID = sbs.sbsID
                    where ps.isFinalized = 1 and ps.pseudosubjectID = ".$request->pseudoSubjectId." and sbs.subjectID = ".$request->subjectId." and sbs.staffID = ".$request->staffId."
                    group by std.studentID,sbs.sbsID,ps.pseudosubjectID,sbs.staffID;";
            }
            else
            {
                $attendanceRules = AttendanceService::getInstance()->getAttendanceRule($request->batchId, $request->semId);    
                $sql_groupBy = "GROUP BY sa.studentID order by sa.rollNo";
                $dateOfJoining = $attendanceRules->dateOfjoining;
                if($request->fromDate && $request->toDate){
                    $sql_dates = $attendanceRules->dateOfjoining ?" AND CASE WHEN sa.studentJoindate IS NOT NULL AND sa.studentJoindate <> '0000-00-00' AND sa.studentJoindate > '".$request->fromDate."' THEN att.attendanceDate BETWEEN sa.studentJoindate AND '".$request->toDate."' ELSE att.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."' END":" AND att.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."'";
                }
                $sql_joiningDate = "";
                if($dateOfJoining)
                {
                    $sql_joiningDate = " and att.attendanceDate >= sa.studentJoinDate ";
                }
                $excludeSql = '';
                if($includeFailed == false)
                {
                    $excludeSql = "AND ba.batchName != 'failed'";
                }
                $sql_attendance = "SELECT sa.studentID,sa.rollNo, sa.studentName,sa.studentJoindate, (COUNT(CASE WHEN (att.isAbsent = 0 OR att.isAbsent = 2) THEN 1 END) / COUNT(att.sbsID)) * 100 AS percentage, ba.batchName, sem.semName,count(distinct att.attendanceDate) as noOfDates
                FROM studentaccount sa
                inner join attendance att on sa.studentID = att.studentID and att.isBlocked = 0 $sql_joiningDate 
                inner join batches ba on  sa.batchID = ba.batchID 
                inner join semesters sem on sem.semID = att.semID 
                WHERE att.batchID = $request->batchId  and att.sbsID = $request->sbsId $sql_dates  $excludeSql GROUP BY sa.studentID order by sa.rollNo";
                
                if($request->includeFailed)
                {
                    $sql_attendance = "SELECT * from (SELECT sa.studentID,sa.rollNo, sa.studentName,sa.studentJoindate, (COUNT(CASE WHEN (att.isAbsent = 0 OR att.isAbsent = 2) THEN 1 END) / COUNT(att.sbsID)) * 100 AS percentage, ba.batchName, sem.semName,count(distinct att.attendanceDate) as noOfDates
                FROM studentaccount sa
                inner join attendance att on sa.studentID = att.studentID and att.isBlocked = 0$sql_joiningDate 
                inner join batches ba on  sa.batchID = ba.batchID 
                inner join semesters sem on sem.semID = att.semID 
                WHERE att.batchID = $request->batchId and att.sbsID = $request->sbsId  $sql_dates GROUP BY sa.studentID
                    UNION 
                    SELECT sa.studentID,sa.rollNo, sa.studentName,sa.studentJoindate, (COUNT(CASE WHEN (att.isAbsent = 0 OR att.isAbsent = 2) THEN 1 END) / COUNT(att.sbsID)) * 100 AS percentage, ba.batchName, sem.semName,count(distinct att.attendanceDate) as noOfDates
                    FROM studentaccount sa
                    inner join attendance att on sa.studentID = att.studentID and att.isBlocked = 0
                    $sql_joiningDate 
                    inner join failed_students fs on fs.studentID = sa.studentID
                    inner join batches ba on  att.batchID = ba.batchID
                    inner join semesters sem on sem.semID = att.semID  
                    WHERE att.sbsID = $request->sbsId  and att.batchID = $request->batchId and fs.previousBatch= $request->batchId $sql_dates GROUP BY sa.studentID) as stattn GROUP BY stattn.studentID order by stattn.rollNo";
                }
                
                
            }
            return $this->executeQueryForList($sql_attendance);
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getHourAttendedStudents($batchId,$semId,$hour,$subbatchId = NULL,$attendanceDate,$considerSem = null){
        $batchId = $this->realEscapeString($batchId);
        $attendanceDate = $this->realEscapeString($attendanceDate);
        $hour = $this->realEscapeString($hour);
        $subbatchId = $this->realEscapeString($subbatchId);
        $semId = $this->realEscapeString($semId);
        if($considerSem)
        {
            $semCheck = "AND semID = $semId";
        }
        else
        {
            $semCheck = "";
        }
        if($subbatchId){
            $sql = "SELECT count(studentID) AS attendanceCount FROM attendance
            WHERE batchID= $batchId $semCheck AND attendanceDate = '$attendanceDate' AND hour = '$hour' AND subbatchId =  $subbatchId AND isAbsent = 0";
        }
        else{
            $sql = "SELECT count(studentID) AS attendanceCount FROM attendance
            WHERE batchID= $batchId $semCheck  AND attendanceDate = '$attendanceDate' AND hour = '$hour'AND isAbsent = 0";
        }
        try{
            $attendanceCount = $this->executeQueryForObject($sql)->attendanceCount;
            return (int)$attendanceCount;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getStudentLastAttendance($request){
        $request = $this->realEscapeObject($request);
        if($request->limit){
            $limit = "limit ".$request->limit;
        }
        $sql = "select at.id as attendanceId,at.attendanceDate,hour,semID as semId,st.studentID as id,st.studentName from attendance at 
        inner join studentaccount st on st.studentID = at.studentID
        where at.isAbsent in (0,2) and at.studentID = '$request->studentId' order by at.attendanceDate desc $limit;";
        try{
            return $this->executeQueryForList($sql);
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        } 
    }
    public function getStudentAttendance($request){
        $request = $this->realEscapeObject($request);
        $at = [];
        $att = [];
        $request->attendanceDate?$at[]="at.attendanceDate = '$request->attendanceDate":"";
        $request->attendanceDate?$att[]="att.attendanceDate = '$request->attendanceDate":"";
        $request->hour?$at[]="at.hour = '$request->hour":"";
        $request->hour?$att[]="att.hour = '$request->hour":"";
        $request->sbsId?$at[]="at.sbsID = '$request->sbsId":"";
        $request->sbsId?$att[]="att.sbsID = '$request->sbsId":"";
        try {
            $sql = "SELECT std.studentID,std.studentName,std.batchID,std.regNo,std.rollNo, at.id AS attendanceId,at.attendanceDate AS date,at.hour,at.sbsID, at.isAbsent,att.studentID as tStudentId,att.attendanceDate AS tDate,att.hour AS tHour,att.sbsID AS tSbsId, att.isAbsent as tIsAbsent 
            FROM studentaccount std
            LEFT JOIN attendance at ON at.studentID = std.studentID ".($at?" AND ".implode(' AND ',$at):"")."
            LEFT JOIN attendance_temporary att ON att.studentID = std.studentID ".($att?" AND ".implode(' AND ',$att):"")."
            WHERE std.studentID = '$request->studentId';"; 
            return $this->executeQueryForList($sql);
        } catch (\Exception $th) {
            throw new ProfessionalException($th->getCode(), $th->getMessage());
        }
    }
    public function getTemoraryAttendanceDetails($request){
        $request = $this->realEscapeObject($request);
        try {
            $sql = "select subbatchID from attendance_confirm_temporary where batchID='$request->batchID' and hour='$request->hour' and attendanceDate='$request->attendanceDate' and semID='$request->semID'";
            $data = $this->executeQueryForList($sql);
            return empty($data)?false:true;
        } catch (\Exception $th) {
            throw new ProfessionalException($th->getCode(), $th->getMessage());
        }
    }
    /**
     * This function calculates absentees percentage of a batch on a day and inserts/updates to the table 'batch_absentees_percent' 
     * @param unknown $batchID
     * @param unknown $date
     */
    function saveBatchAbsenteespercentByBatch($batchID, $date)
    {
        try{
            $sql = "SELECT id FROM batch_absentees_percent WHERE att_date='$date' and batchID='$batchID'";
            $data = $this->executeQueryForObject($sql);
            if(count($data))
            {
                $id = $data->id;
                $sql_update = "UPDATE batch_absentees_percent SET absentees_percent = (SELECT (select COUNT(studentID) from attendance where attendanceDate='$date' and batchID='$batchID' and isAbsent = 1)/(select COUNT(studentID) from attendance where attendanceDate='$date' and batchID='$batchID') *100) WHERE id = '$id'";
                $this->executeQuery($sql_update);
            }
            else
            {
                $sql_insert = "INSERT INTO batch_absentees_percent (batchID, absentees_percent, att_date) VALUES(".$batchID.",(SELECT (select COUNT(studentID) from attendance where attendanceDate='$date' and batchID='$batchID' and isAbsent = 1)/(select COUNT(studentID) from attendance where attendanceDate='$date' and batchID='$batchID') *100), '$date')";
                $this->executeQuery($sql_insert);
            }
        } catch (\Exception $th) {
            throw new ProfessionalException($th->getCode(), $th->getMessage());
        }
    }
    public function getStudentsAttendanceByRequest($request){
        $request = $this->realEscapeObject($request);
        
        $subColumns = ["st.studentID","st.studentName","st.studentAccount","st.rollNo","at.attendanceDate"];
        $columns = [];
        
        if(empty($request->attendanceRules))
        {
            if($request->ruleBatchId && $request->ruleSemId){
                $attendanceRules = $this->getAttendanceRule($request->ruleBatchId, $request->ruleSemId);
            }
        }
        else
        {
            $attendanceRules = $request->attendanceRules;
        }
        $attendanceRules->classStartsFrom = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
        $attendanceRules->classEnds = date('Y-m-d', strtotime($attendanceRules->classEnds));
        //batchID,semID,dateOfjoining,morninghours,classStartsFrom,classEnds,isActive,halfdayHourCount,fulldayHourCount
        
        if($request->mustTakeAttendanceRule){
            if(empty($attendanceRules))
            {
                throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Attendance rules not defined");
            }
        }
        $fromDateRule = !empty($attendanceRules->classStartsFrom) ? new \DateTime($attendanceRules->classStartsFrom) : null;
        $toDateRule = !empty($attendanceRules->classEnds) ? new \DateTime($attendanceRules->classEnds) : null;
        $request->fromDate = $request->fromDate?date('Y-m-d', strtotime($request->fromDate)):null;
        $request->toDate = $request->toDate?date('Y-m-d', strtotime($request->toDate)):date('Y-m-d');
        //if $fromDateRule is valid, $fromDate is smaller than $fromDateRule and if attendance rule is activate then take $fromDateRule as $fromDate
        if ($fromDateRule && strtotime($attendanceRules->classStartsFrom) > 0 && $attendanceRules->isActive) {
            if(empty($request->fromDate)){
                $request->fromDate = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
            }
            else if (CommonUtil::isFromDateSameOrBeforeToDate($request->fromDate, $attendanceRules->classStartsFrom)) {
                $request->fromDate = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
            }
        }
        //if $toDateRule is valid, $todate is greater than $toDateRule and if attendance rule is activate then take $toDateRule as $todate
        if ($toDateRule && strtotime($attendanceRules->classEnds) > 0 && $attendanceRules->isActive) {
            if(empty($request->toDate)){
                $request->toDate = date('Y-m-d', strtotime($attendanceRules->classEnds));
            }
            else if (CommonUtil::isFromDateSameOrBeforeToDate($attendanceRules->classEnds, $request->toDate)) {
                $request->toDate = date('Y-m-d', strtotime($attendanceRules->classEnds));
            }
        }
        
        if((int)$attendanceRules->halfdayHourCount && (int)$attendanceRules->fulldayHourCount){
            $subColumns = array_merge($subColumns,["IF(SUM(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->halfdayHourCount.",'.5',0) AS present_evening","IF(sum(IF((find_in_set(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->fulldayHourCount.",'.5',0) AS present_morning","IF(sum(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->halfdayHourCount.",'.5',0) + IF(sum(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->fulldayHourCount.",'.5',0) AS sum_of_session"]);
        }else{
            $morninghours = (int)$attendanceRules->morninghours?$attendanceRules->morninghours:$request->morninghours;
            $subColumns = array_merge($subColumns,["IF(FIND_IN_SET('1',group_concat(IF(at.hour <= ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS present_morning","IF(FIND_IN_SET('1',group_concat(IF(at.hour > ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS present_evening","IF(FIND_IN_SET('1',group_concat(IF(at.hour <= ".(int)$morninghours.",at.isAbsent,null))),0,'.5') + IF(FIND_IN_SET('1',group_concat(if(at.hour > ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS sum_of_session"]);
        }
        $dlWorkFlow = CommonService::getInstance()->getSettings(SettingsConstents::LEAVE_MANAGEMENT, SettingsConstents::ENABLE_LEAVE_WORKFLOW);
        // $dlHourCount = $dlWorkFlow?"SUM(IF(at.isAbsent = 2 AND dl.dlrName is not null,1,0)) AS dl_hourIds":"SUM(IF(at.isAbsent = 2,1,0)) AS dl_hourIds";
        $dlHourCount = "SUM(IF(at.isAbsent = 2,1,0)) AS dl_hourIds";
        $subColumns = array_merge($subColumns,["COUNT(at.hour) AS hourIds","SUM(IF(FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked != 1,1,0)) AS present_hourIds","SUM(IF(FIND_IN_SET(at.isAbsent,'0') AND at.isBlocked != 1,1,0)) AS attended_hourIds",$dlHourCount,"SUM(IF(at.isAbsent = 1,1,0)) AS isAbsent"]);
        
        $where = [];
        $request->batchId?$where[] = "b.batchID = '".$request->batchId."'":null; 
        $request->studentId?$where[] = "st.studentID = '".$request->studentId."'":null; 
        $request->semId?$where[] = "at.semID = '".$request->semId."'":null; 
        $request->studentIds?$where[] = "st.studentID in (".implode(',',$request->studentIds).")":null; 
        $request->currentSem?$where[] = "b.semID = at.semID":null; 
        $request->sbsId?$where[] = "sbs.sbsID = '".$request->sbsId."'":null; 
        
        if($request->fromDate && $request->toDate){
            // Adding date conditions 
            $where[] = $attendanceRules->dateOfjoining ?"CASE WHEN st.studentJoindate IS NOT NULL AND st.studentJoindate <> '0000-00-00' AND st.studentJoindate > '".$request->fromDate."' THEN at.attendanceDate BETWEEN st.studentJoindate AND '".$request->toDate."' ELSE at.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."' END":"at.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."'";
            $subColumns = array_merge($subColumns,["IF(st.studentJoindate IS NOT NULL AND st.studentJoindate <> '0000-00-00' AND st.studentJoindate > '".$request->fromDate."',st.studentJoindate,'".$request->fromDate."') AS fromDate","'".$request->toDate."' AS toDate"]);
        }else{
            $subColumns = array_merge($subColumns,["null AS fromDate","null AS toDate"]);
        }
        $joinSbs = "INNER JOIN sbs_relation sbs ON sbs.sbsID = at.sbsID";
        if($request->subjectId){
            $joinSbs = "INNER JOIN sbs_relation sbs ON sbs.sbsID = at.sbsID AND b.batchID = sbs.batchID";
            $where[] = "sbs.subjectID = '$request->subjectId'";
        }
        
        $sql = 
            "SELECT studentID,studentName,studentAccount,rollNo,
            COUNT(attendanceDate) AS date_count,
            SUM(IF(present_morning OR present_evening,1,0)) AS present_days,
            ROUND((SUM(IF(present_morning OR present_evening,1,0))/count(attendanceDate))*100,2) AS present_days_percentage,
            SUM(sum_of_session) AS session_present_count,
            ROUND((sum(sum_of_session)/COUNT(attendanceDate))*100,2) AS percentage_of_session,
            COUNT(attendanceDate) - SUM(IF((present_morning = .5 and present_evening = 0) OR (present_morning = 0 and present_evening = .5),0,1)) AS half_day,
            COUNT(attendanceDate) - SUM(IF(present_morning = 0 AND present_evening = 0,0,1)) AS full_day,
            SUM(hourIds) AS hourCount,
            SUM(present_hourIds) AS present_hour_count,
            SUM(attended_hourIds) AS attended_hour_count, 
            SUM(isAbsent) AS absent_hour_count, 
            SUM(dl_hourIds) AS dl_hour_count,
            ROUND((sum(present_hourIds)/SUM(hourIds))*100,2) AS hour_percentage,
            GROUP_CONCAT(distinct fromDate) as fromDate,
            GROUP_CONCAT(distinct toDate) as toDate
            FROM (
                SELECT  ".implode(',', $subColumns)."
                FROM studentaccount st 
                    INNER JOIN attendance at ON at.studentID = st.studentID
                    INNER JOIN batches b ON b.batchID = st.batchID
                    ".$joinSbs."
                    LEFT JOIN duty_leave_remarks dl on dl.dlrId = at.dlrId and dlrName is not null and at.isAbsent = 2
                    " . ($where ? " WHERE " . implode(' AND ', $where) : "") . "
                GROUP BY st.studentID, at.attendanceDate
                ORDER BY at.hour
            ) AS temp 
            GROUP BY studentID ORDER BY rollNo;";
        try{
            return $this->executeQueryForList($sql);
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getStudentsAttendance($request){
        try{
            $studentID = $_SESSION['studentID']?$_SESSION['studentID']:$request->studentId;
            $joiningDate = StudentService::getInstance()->getStudentDetailsById($studentID)->studentJoindate;
            //handling late comer using attendance rule
            $attendanceRule = $request->attendanceRules;
            $dateOfjoining = $attendanceRule->dateOfjoining;
            if ($dateOfjoining) {
                if (strtotime($joiningDate) > strtotime($request->fromDate)) {
                    $hisfromDate = $joiningDate;
                } else {
                    $hisfromDate = $request->fromDate;
                }
            } else {
                $hisfromDate = $request->fromDate;
            }
            $morninghours = $request->attendanceRules->morninghours;
            $total_attendance = 0;
            $total_workingdays = 0;
            $halfday_absent = 0;
            $fullday_absent = 0;
            $request = $this->realEscapeObject($request);
            $sql = "SELECT DISTINCT(attendanceDate) from attendance where semID=\"$request->ruleSemId\" and batchID=\"$request->ruleBatchId\" and attendanceDate BETWEEN '$hisfromDate' AND '$request->toDate' ORDER BY attendanceDate ";
            $dates = $this->executeQueryForList($sql);
            GLOBAL $ATTENDANCE_HOURS;
            if($dates)
            {
                foreach($dates as $dat)
                {
                    $morning_session = true;
                    $afternoon_session = true;
                    $attendance_today = 0;
                    $date = $dat->attendanceDate;
                    $attended = 0;
                    for ($i = 1; $i <= $ATTENDANCE_HOURS; $i++)
                    {
                        $block_sql = "SELECT t1.isAbsent, t1.isBlocked from attendance t1 where  t1.attendanceDate='$date' and t1.batchID=\"$request->ruleBatchId\" and t1.hour=$i and t1.semID=\"$request->ruleSemId\" and t1.studentID=$studentID ";
                        $status = $this->executeQueryForObject($block_sql);
                        if($status)
                        {
                            $attended = 1;
                            if ($status->isAbsent == 1 || $status->isBlocked == 1) {
                                if ($i <= $morninghours) {
                                    $morning_session = false;
                                } else {
                                    $afternoon_session = false;
                                }
                            }
                            
                        }
                    }
                    if ($morning_session && $attended) {
                        $attendance_today = .5;
                    }
                    if ($afternoon_session && $attended) {
                        $attendance_today = $attendance_today + .5;
                    }
                    if ($attended) {
                        $total_workingdays++;
                    }
                    if ($attendance_today == .5)
                        $halfday_absent++;
                    if ($attendance_today == 0 && $attended)
                        $fullday_absent++;
                    
                    
                    $total_attendance = $total_attendance + $attendance_today;
                }
                if ($total_workingdays != 0) {
                    $percent_attendance = ($total_attendance / $total_workingdays) * 100;
                } else {
                    $percent_attendance = 0;
                }
            }
            $response = new stdClass();
            $response->session_present_count = $total_attendance;
            $response->date_count = $total_workingdays;
            $response->percentage_of_session = $percent_attendance;
            $response->half_day=$halfday_absent;
            $response->full_day=$fullday_absent;
            return $response;
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get pseudo subject attendance marked student by request
     */
    function getPseudoSubjectAttendanceMarkedStudents($request)
    {
        $request = $this->realEscapeObject($request);
        $where = [];
        $request->attendanceDate?$where[]="at.attendanceDate = '$request->attendanceDate":"";
        $request->pseudoSubjectId?$where[]="psbs.pseudosubjectID = '$request->pseudoSubjectId":"";
        $request->hour?$where[]="at.hour = '$request->hour":"";
        $request->subbatchId?$where[]="sub.subbatchID = '$request->subbatchId":"";
        try {
            $sql = "SELECT std.studentID as studentId,std.studentName as studentName,std.batchID as batchId,std.rollNo,at.isAbsent as isAbsent,st.staffID as staffId,st.staffName as staffName,at.hour ,at.batchID as batchId,at.semID as semId,concat(at.studentID,at.hour,at.attendanceDate,at.batchID,at.semID) as attendanceId,dlr.dlrId,dlr.dlrName,dlr.dlrDescription,at.staffID, at.batchID, at.semID, bat.batchName, sem.semName as subjectSem, sub.subbatchID as subBatchId, at.sbsID as sbsId 
            from attendance at 
            inner join pseudosubjects_sbs psbs on psbs.sbsID = at.sbsID 
            inner join sbs_relation sbs on sbs.sbsID = psbs.sbsID
            inner join staffaccounts st on st.staffID = sbs.staffID
            inner join semesters sem on  sem.semID = at.semID 
            inner join subbatches sub on sub.psID = psbs.pseudosubjectID and sub.batchID = at.batchID and sub.semID = at.semID
            inner join batches bat on bat.batchID = at.batchID 
            inner join studentaccount std on std.studentID = at.studentID and std.batchID = at.batchID
            inner join pseudosubjects_students psstd on psstd.pseudosubjectID = psbs.pseudosubjectID and psstd.studentID = std.studentID
            inner join subbatch_student subst on subst.subbatchID = sub.subbatchID and psstd.studentID = subst.studentID
            LEFT JOIN duty_leave_remarks dlr on dlr.dlrID = at.dlrID
            where ps.isFinalized = 1 ".($where?" AND ".implode(' AND ',$where):"")."
            group by std.studentID,at.attendanceDate,at.hour;";
            return $this->executeQueryForList($sql);
        } catch (\Exception $th) {
            throw new ProfessionalException($th->getCode(), $th->getMessage());
        }
    }
    /**
     * Check Attendance Details by Request
     * @param request
     * @return Boolean
     * @throws ProfessionalException
     */
    public function checkAttendanceDetailsByRequest($request)
    {
        
        $sql = "SELECT 
                    id 
                FROM 
                    attendance 
                WHERE
                    batchID = '$request->batchID'
                    AND sbsID = '$request->sbsID'
                    AND semID = '$request->semID'
                    AND hour = '$request->hour'
                    AND attendanceDate = '$request->timetableDate'
                    ";
        try {
            $result = $this->executeQueryForList($sql);
            if($result){
                return true;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return false;
    }
    /**
     * get Attendance Details by Request
     * @param Integer/Date $sbsID, $fromDate, $toDate
     * @return Array AttendanceList
     * @throws ProfessionalException
     */
    public function getStudentAttendanceDetailsBySbsIdAndDateRange($sbsID, $fromDate, $toDate)
    {
        
        $sql = "SELECT 
                    id,
                    studentID,
                    hour,
                    attendanceDate,
                    semID,
                    batchID,
                    isAbsent,
                    staffID,
                    sbsID 
                FROM 
                    attendance 
                WHERE
                    sbsID = '$sbsID'
                    AND attendanceDate BETWEEN '$fromDate' AND '$toDate'
                ORDER BY attendanceDate ASC
                    ";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return false;
    }
    /**
     * get Staffs that Marked the attendance for a particular hour
     * @param Object $request 
     * @return Array Staffs
     * @throws ProfessionalException
     */
    public function getStaffAttendanceHours($request){
        $request = $this->realEscapeObject($request);
        $cond = "";
        $cond .= $request->batchId?"and at.batchID ='".$request->batchId."'":""; 
        $cond .= $request->semId?"and at.semID ='".$request->semId."'":"";
        $cond .= $request->sbsId?"and at.sbsID ='".$request->sbsId."'":"";
        $cond .= $request->attendanceDate?"and at.attendanceDate ='".$request->attendanceDate."'":"";
        $cond .= $request->hour?"and at.hour ='".$request->hour."'":"";
        $sql = "select at.attendanceDate,at.hour,at.day,at.semID,at.batchID,at.sbsID,at.subbatchId,sbsr.subjectID,sta.staffName,IF(ps.pseudosubjectID IS NULL,concat(s.subjectDesc,' (',s.subjectName,') '),ps.subjectName) as subjectName from attendance at inner join staffaccounts sta on sta.staffID = at.staffID left join pseudosubjects_sbs pssbs on pssbs.sbsID = at.sbsID left join pseudosubjects ps on ps.pseudosubjectID = pssbs.pseudosubjectID inner join sbs_relation sbsr on sbsr.sbsID = at.sbsID inner join subjects s on s.subjectID = sbsr.subjectID where 1=1 $cond group by at.attendanceDate,at.hour,at.batchID,at.semID,at.sbsID";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return false;
    }
    /**
     * Create attendance delete log from HOD,ERP admin,Principal
     * @param Attendance $attendanceDetails
     * @param string $subj_attendance
     * @return boolean
     * @throws ProfessionalException
     */
    public function createAttendanceDeleteLogFromErpAdmin($attendanceDetails, $subj_attendance = null)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $staffId = $this->realEscapeString($attendanceDetails->deleteStaff);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $attendanceDetails->hour ? $this->realEscapeString($attendanceDetails->hour) : 'null';
        $sql = "insert into delete_attendance_log (staffID,batchID,semID,attendanceDate,hour) values ($staffId$batchId$semId, '" . $attendanceDate . "', $hour)";
        try {
            $this->executeQueryForObject($sql);
            $this->deleteAttendanceFromErpAdmin($attendanceDetails);
            $this->deleteAttendanceConfirm($attendanceDetails);
            if ($subj_attendance) {
                $this->deleteAttendanceConfirmTemporary($attendanceDetails);
                $this->deleteAttendanceTemporaryFromErpAdmin($attendanceDetails);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * Delete attendance from HOD,ERP admin,Principal
     * @param Attendance $attendanceDetails
     * @return object|NULL|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function deleteAttendanceFromErpAdmin($attendanceDetails)
    {
        $attendanceDetails = $this->realEscapeObject($attendanceDetails);
        $batchId = $attendanceDetails->batchID;
        $semId = $attendanceDetails->semID;
        $staffId = $attendanceDetails->MarkingStaffID;
        $attendanceDate = $attendanceDetails->attendanceDate;
        $hour = $attendanceDetails->hour;
        $sbsId = $attendanceDetails->sbsID;
        if (!empty($staffId)) {
            $sql_staff = " AND staffID = $staffId";
        }
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $confirmedStaffDetails = $this->getAttendanceConfirmedStaffDetails($batchId, $semId, $hour, $attendanceDate, 0, $sbsId);
        if (count($confirmedStaffDetails) == 1) {
            $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs";
        } else {
            if ($attendanceDetails->subbatchId != NULL) {
                if ($attendanceDetails->subbatchId == 0) {
                    $subbatchIds = array_map(function ($obj) {
                        return $obj->subbatchID;
                    }, $confirmedStaffDetails);
                    $subbatchIds = array_unique($subbatchIds);
                    $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs AND studentID NOT IN(select studentID from subbatch_student where subbatchID IN(" . implode(',', $subbatchIds) . "))";
                } else {
                    $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs AND studentID IN(select studentID from subbatch_student where subbatchID=$attendanceDetails->subbatchId)";
                }
            } else {
                $sql = "delete from attendance where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sbs";
            }
        }
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Delete from attendance_temporary from HOD,ERP admin,Principal
     * @param Attendance $attendanceDetails
     * @return \com\linways\base\dto\MySqlResult
     * @throws ProfessionalException
     */
    public function deleteAttendanceTemporaryFromErpAdmin($attendanceDetails)
    {
        $batchId = $this->realEscapeString($attendanceDetails->batchID);
        $semId = $this->realEscapeString($attendanceDetails->semID);
        $staffId = $this->realEscapeString($attendanceDetails->MarkingStaffID);
        $attendanceDate = $this->realEscapeString($attendanceDetails->attendanceDate);
        $hour = $this->realEscapeString($attendanceDetails->hour);
        $subbatchId = $this->realEscapeString($attendanceDetails->subbatchId);
        $sbsId = $this->realEscapeString($attendanceDetails->sbsID);
        if (!empty($staffId)) {
            $sql_staff = " AND staffID = $staffId";
        }
        if (!empty($hour)) {
            $sql_hour = " AND hour=$hour";
        }
        if ($subbatchId != NULL) {
            $sql_sub = " AND subbatchID=$subbatchId";
        }
        if (!empty($sbsId)) {
            $sql_sbs = " AND sbsID = $sbsId";
        }
        $sql = "delete from attendance_temporary where batchID=$batchId and attendanceDate=\"$attendanceDate\" and semID=$semId $sql_staff $sql_hour $sql_sub $sql_sbs";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * generate Subject Wise Attendance Details by batchId amd semId
     * @param Object 
     * @return Array AttendanceList
     * @throws ProfessionalException
     */
    public function generateSubjectWiseAbsenteesAttendanceDetails($request)
    {
        if(!$request->batchId || !$request->semId){
            throw new ProfessionalException("INVALID_DATA","INVALID_DATA");
        }
        try {
        $date = date('Y-m-d');
        $sql = "SELECT at.attendanceDate,at.hour,at.semID,at.batchID,
                stf.staffName,
                COUNT(at.hour) AS total_hours,
                SUM(IF(FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked != 1,1,0)) AS present_hourIds,
                SUM(IF(FIND_IN_SET(at.isAbsent,'0') AND at.isBlocked != 1,1,0)) AS attended_hourIds,
                SUM(IF(at.isAbsent = 1,1,0)) AS isAbsent,
                ROUND((SUM(IF(FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked != 1,1,0))/COUNT(at.hour))*100,2) AS hour_percentage,
                (group_concat(distinct IF(at.isAbsent = 1,concat(sa.rollNo,'-',sa.studentName),NULL))) as absentees,
                sub.subjectName,
                sub.subjectDesc,
                sub.subjectID
                from attendance at
                inner join sbs_relation sbs on sbs.sbsID = at.sbsID and at.batchID = sbs.batchID and sbs.semID = at.semID
                inner join subjects sub on sub.subjectID = sbs.subjectID
                inner join studentaccount sa on sa.studentID = at.studentID
                inner join staffaccounts stf on stf.staffID = sbs.staffID
                where 
                at.batchID = '$request->batchId' and at.semID = '$request->semId' AND at.attendanceDate = '$date'
                group by sbs.subjectID,at.hour ";
        
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return false;
    }
    public function getAttendanceDetailsOfStudent($batchId, $semId, $studentId, $startDate = null, $endDate = null)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $studentId = $this->realEscapeString($studentId);
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $considerDutyLeave = $this->realEscapeString($considerDutyLeave);
        if ( empty ( $batchId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Batch can not be null");
        }
        if ( empty ( $semId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Sem can not be null");
        }
        if ( empty ( $studentId ) ) {
            throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Student can not be null");
        }
        $sqlConditions = "";
        $sqlDutyLeaveConditions = "";
        
        if($startDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(att.attendanceDate) >= UNIX_TIMESTAMP('$startDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.start_date) >= UNIX_TIMESTAMP('$startDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.end_date) >= UNIX_TIMESTAMP('$startDate') ";
        }
        if($endDate){
            $sqlConditions .= " AND UNIX_TIMESTAMP(att.attendanceDate) <= UNIX_TIMESTAMP('$endDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.start_date) <= UNIX_TIMESTAMP('$endDate') ";
            $sqlDutyLeaveConditions .= " AND UNIX_TIMESTAMP(sla.end_date) <= UNIX_TIMESTAMP('$endDate') ";
        }
        $sql = "SELECT att.attendanceDate,att.`hour`,att.`day`,att.isAbsent,att.staffID,att.sbsID,att.csID,att.isBlocked,att.subbatchId,att.dlrId,sa.staffName,sbsr.subjectID
        FROM
            attendance att
        INNER JOIN staffaccounts sa ON
            sa.staffID = att.staffID 
        INNER JOIN sbs_relation sbsr ON 
            sbsr.sbsID = att.sbsID
        WHERE
            att.studentID = $studentId AND att.batchID = $batchId AND att.semID = $semId $sqlConditions 
        ";
        $sqlDutyLeave = "SELECT DISTINCT a.attendanceDate,
            sla.id,
            sla.leave_type_Id AS leaveTypeId,
            sla.session_key AS sessionKey,
            sla.start_date AS startDate,
            sla.end_date AS endDate,
            sla.applied_date AS appliedDate,
            sla.noof_days AS noOfDays,
            sla.description,
            sla.reason,
            sla.status,
            sla.lin_resources_id AS linResourceId,
            sla.userType,
            sla.workflowInstanceId,
            sla.dlrId,
            slt.id,
            slt.code,
            slt.name,
            slt.description,
            slt.isDL
        FROM
            student_leave_application sla
        INNER JOIN student_leave_type slt ON
            slt.id = sla.leave_type_Id and slt.isActive=1
        INNER JOIN attendance a
            ON sla.student_Id = a.studentID
            AND a.attendanceDate BETWEEN sla.start_date AND sla.end_date
        WHERE
            sla.student_Id = $studentId
            AND sla.status = 'APPROVED'
            $sqlDutyLeaveConditions ";
        try 
        {
            $attendanceDetails = $this->executeQueryForList($sql);
            $dutyLeaveDetails = $this->executeQueryForList($sqlDutyLeave);
            
            foreach ($attendanceDetails as $attendance) {
                $sessionKeyFound = false;
                $studentAttendance[$attendance->attendanceDate]->date = $attendance->attendanceDate;
                $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour] = $attendance;
                $dutyLeaveDateArray = array_filter($dutyLeaveDetails,function ($dutyLeave) use ($attendance){
                    return $dutyLeave->attendanceDate == $attendance->attendanceDate;
                });
                $dutyLeaveHour = array_values(array_filter($dutyLeaveDateArray,function($dutyHour) use ($attendance){
                    return str_contains($dutyHour->sessionKey,$attendance->hour);
                }));
                //$dutyLeaveArrayKey = array_search($attendance->attendanceDate, array_column($dutyLeaveDetails, 'attendanceDate'));
                $sessionKeys = json_decode("[".$dutyLeaveHour[0]->sessionKey."]");
                if (!empty($sessionKeys)){
                    $sessionKeyFound = in_array($attendance->hour, $sessionKeys);
                }
                if ($dutyLeaveHour !== false && $sessionKeyFound) {
                    $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour]->dutyLeave = $dutyLeaveHour[0];
                }
                else{
                    $studentAttendance[$attendance->attendanceDate]->hour[$attendance->hour]->dutyLeave = null;
                }
            }
        } 
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentAttendance;
    }
    public function grantStudentAttendance($request){
        $request = $this->realEscapeObject($request);
        $set = [];
        $cond = [];
        $cond[] = " WHERE 1=1 ";
        $set[] = "SET updatedDate = utc_timestamp()";
        if(!empty($request->isAbsent != '')){
            $set[] = " isAbsent = ".$request->isAbsent;
        }
        if(!empty($request->staffId)){
            $set[] = " updatedBy = ".$request->staffId;
        }
        if(!empty($request->batchId)){
            $cond[] = " batchID = ".$request->batchId;
        }
        if(!empty($request->semId)){
            $cond[] = " semID = ".$request->semId;
        }
        if(!empty($request->hour)){
            $cond[] = " hour = ".$request->hour;
        }
        if(!empty($request->attendanceDate)){
            $cond[] = " attendanceDate = '".$request->attendanceDate."'";
        }
        if(!empty($request->dlrId)){
            $set[] = " dlrId = ".$request->dlrId;
        }
        if(!empty($request->studentIds)){
            $cond[] = " studentID in (".implode(",",$request->studentIds).") ";
        }
        if(!empty($request->id)){
            $cond[] = " id = $request->id ";
        }
        
        
        $sql = "UPDATE attendance ";
        $sqlSet = implode(",",$set);
        $sqlCond = implode(" AND ",$cond);
        $query = $sql.$sqlSet.$sqlCond;
        try 
        {
            return $this->executeQuery($query,true);
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get student attendance details for a date range
     * @param int $batchId
     * @param int $semId
     * @param string $fromDate
     * @param string $toDate
     * @return object|array|\com\linways\base\util\$objectList[]
     * @throws ProfessionalException
     */
    public function getAStudentAttDetailsInDateRange($request)
    {
        $batchId = $this->realEscapeString($request->batchId);
        $semId = $this->realEscapeString($request->semId);
        $fromDate = $this->realEscapeString($request->fromDate);
        $toDate = $this->realEscapeString($request->toDate);
        $studentId = $this->realEscapeString($request->studentId);
        $sortByColumn = $request->sortByColumn?$request->sortByColumn:'rollNo';
        $subjectId = $this->realEscapeString($request->subjectId);
        $semDetails = SemesterService::getInstance()->getSemDetailsBySemId($semId);
        $cond = "";
        if($subjectId){
            $cond .= " AND  sbs.subjectID = $subjectId ";
        }
        $isCurrentSem = SemesterService::getInstance()->isCurrentSemester($batchId, $semId);
        if ($isCurrentSem) {
            $sql = "SELECT sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, 
            sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  
            (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, 
            att.staffID, att.id as attendanceId, ac.sbsID , s.subjectDesc AS subjectName  
            from attendance_confirm ac inner join  
            studentaccount sa on sa.batchID = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' 
            left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  
            inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID 
            inner join sbs_relation sbs on sbs.sbsID = att.sbsID
            left join subjects s ON s.subjectID = sbs.subjectID
            where joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and sa.studentID = $studentId $cond
            group by ac.attendanceDate ,ac.hour
            order by sa." . $sortByColumn . ", ac.attendanceDate, ac.hour;";
        } else {
            $sql = "SELECT sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, att.staffID, att.id as attendanceId, ac.sbsID  , s.subjectDesc AS subjectName 
            from attendance_confirm ac inner join  
            studentaccount sa on sa.batchID = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' 
            left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  
            inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID 
            inner join sbs_relation sbs on sbs.sbsID = att.sbsID
            left join subjects s ON s.subjectID = sbs.subjectID
            where  joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and sa.studentID = $studentId  
            union select sa.studentID, sa.studentAccount, sa.studentName, sa.studentEmail, sa.batchID, sa.deptID, sa.admissionNo, sa.rollNo, sa.regNo, ac.attendanceDate, ac.hour,  (case when isAbsent = 1 then  'A' when isBlocked = 1 then  'A' when isAbsent = 0 then  'P'  when isAbsent = 2 then 'DL' end )as isAbsent, att.staffID, concat(ac.attendanceDate, ac.hour) as attendanceId, ac.sbsID  , s.subjectDesc AS subjectName
            from attendance_confirm ac inner join failed_students fs on fs.previousBatch = ac.batchID and ac.attendanceDate between '" . $fromDate . "'  and '" . $toDate . "' 
            left join semesters fsem on fsem.semID = fs.failedInSemester 
            left join studentaccount sa on sa.studentID = fs.studentID 
            left join attendance att on sa.studentID = att.studentID and ac.attendanceDate = att.attendanceDate and ac.hour = att.hour  
            inner join sbs_relation sbs on sbs.sbsID = att.sbsID
            inner join semesters joinedSem on sa.joiningSemId = joinedSem.semID 
            left join subjects s ON s.subjectID = sbs.subjectID
            where  joinedSem.orderNo <= " . $semDetails->orderNo . " and ac.batchID = " . $batchId . " and ac.semID = " . $semId . " and fsem.orderNo > " . $semDetails->orderNo . " and sa.studentID = $studentId $cond
            group by ac.attendanceDate ,ac.hour 
            order by " . $sortByColumn . ", attendanceDate, hour";
        }
        try {
            return $this->executeQueryForList($sql,$this->mapper[AttendanceServiceMapper::GET_STUDENT_ATTENDANCE_DETAILS_BY_DATE]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Delete Attendance by Id
     * @param int $attendanceId
     * @throws ProfessionalException
     */
    public function deleteAttendanceByattendanceId($attendanceId)
    {
        try {
            if ( empty ( $attendanceId ) ) {
                throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Attendance cannot be null");
            }
            $sql = "DELETE from attendance where id = '$attendanceId'";
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get attendance taken status
     * @param $request
     */
    public function getAttendanceDetailsByRequest($request)
    {
        $request = $this->realEscapeObject($request);
        global $COLLEGE_CODE;
        $query="select ehas.studentID from exam_hall_arranged_students ehas inner join exam_attendance ea on ehas.examID=ea.examID and ehas.studentID=ea.studentID inner join exam e on ehas.examID=e.examID where e.examDate='$request->examDate' and ehas.hallID=$request->hallId";
        if($request->typeId)
        {
            $query.=" and e.examTypeID=$request->typeId";
        }
        if ($COLLEGE_CODE == "SCEK") {
            if($request->fromTime && $request->toTime){
                $query .= " and STR_TO_DATE( e.examStartTime, '%l:%i %p') between '$request->fromTime' and '$request->toTime'";
            }
        }else{
            if($request->unixtime_start && $request->unixtime_end){
                $query .= " and e.unixtime_start between '$request->unixtime_start' and '$request->unixtime_end'";
            }
        }
        
        try{
            $response = $this->executeQueryForList($query);
            return $response;
        }catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     *  
     */
    public function academicAuditReportForStaff($batchList, $semId, $subjectCategoryIds){
        if(empty($batchList)){
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS, "Batch list is empty");
        }
        if(empty($semId)){
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS, "Sem not found");
        }
        if(empty($subjectCategoryIds)){
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS, "subjectCategory list is empty");
        }
        try{
            
            $sql = "SELECT temp.batchID,GROUP_CONCAT(DISTINCT temp.batchNames) AS batchNames, temp.patterncourseID, temp.subjectID, temp.patterncourseCode, temp.staffID, temp.staffName, temp.subjectName,  temp.credit, temp.auditReportConstant, count(DISTINCT temp.attendanceId) AS hourTaken, if(temp.pseudosubjectID,CONCAT('PSEUDO',temp.pseudosubjectID) ,CONCAT('BATCH',temp.batchID,'SUB',temp.subjectID)) as combination, temp.subbatchID FROM (
                SELECT sr.batchID, bt.patterncourseID, sr.subjectID, pd.patterncourseCode, sa.staffID, sa.staffName, if(p.pseudosubjectID,concat(p.subjectName,'(',sb.subjectName,')'),sb.subjectName) as subjectName,  es.credit, JSON_EXTRACT(`extraSettings` , '$.auditReportConstant') AS auditReportConstant, ac.id AS attendanceId, GROUP_CONCAT(DISTINCT sr.sbsID) as sbsIDs, GROUP_CONCAT(DISTINCT bt.batchName) as batchNames,p.pseudosubjectID,concat(ac.subbatchID) as subbatchID
                FROM attendance_confirm ac 
                    INNER JOIN sbs_relation sr ON sr.sbsID=ac.sbsID 
                    INNER JOIN `batches` bt ON bt.batchID=sr.batchID 
                    INNER JOIN staffaccounts sa ON sa.staffID=ac.staffID 
                    INNER JOIN subjects sb ON sb.subjectID=sr.subjectID 
                    INNER JOIN subject_category sc ON sc.subjectcatID=sb.subjectcatID 
                    INNER JOIN pattern_deptcourses pd ON pd.patterncourseID=bt.patterncourseID 
                    LEFT JOIN exam_subjectcredit es ON es.batchID=bt.batchID AND es.semID=sr.semID AND es.subjectID=sr.subjectID 
                    LEFT JOIN subbatches sub ON sub.subbatchID = ac.subbatchID and sub.psID <> 0
                    LEFT JOIN pseudosubjects p ON p.pseudosubjectID = sub.psID 
                    LEFT JOIN subbatches s ON s.subbatchID = ac.subbatchID AND s.psID = p.pseudosubjectID 
                WHERE sc.subjectcatID IN (".implode(', ', $subjectCategoryIds).") AND bt.batchID IN (".implode(', ', $batchList).") AND sr.semID='$semId
                GROUP BY if(p.pseudosubjectID,p.pseudosubjectID,sr.batchID),ac.attendanceDate ,ac.`hour`,sr.staffID
            ) as temp
            GROUP BY temp.staffID, temp.subjectID,IF(temp.pseudosubjectID,temp.pseudosubjectID,temp.batchID);";
            return $this->executeQueryForList($sql);
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * 
     * 
     */
     public function getSubjectWiseAttendanceDetails($request)
     {
        if (empty($request->studentId)) {
          if (empty($request->studentId)) {
            $throwMessage[] = "Student Details";
          }
          throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS, "Request contains insufficient parameters. ( " . implode(', ', $throwMessage) . " )");
        }
        try {
        // ************************************************************************************************************************************************
        // FOR TAKING THE ATTENDANCE OF THE STUDENTAFTER THE JOINING DATE
        // *****************************************************************************************************************************************************
            
        $query = "SELECT vaar.properties->>'$.attendanceFromJoiningDate' as attendanceFromJoiningDate, vaar.start_date from v4_ams_attendance_rules vaar
        INNER JOIN `groups` g ON g.id = vaar.batch_groups_id
        INNER JOIN student_program_account spa ON spa.current_batch_id = g.id
        INNER JOIN studentaccount s ON s.studentID = spa.student_id
        WHERE s.studentID = '$request->studentId";
        if ($request->termId) {
        $query .= " AND vaar.academic_term_id = '$request->termId'";
        }else{
        $query .= " AND g.academic_term_id = vaar.academic_term_id ";
        }
        
        $attendanceFromJoiningDate = $this->executeQueryForObject($query);
        $studenAttendanceDateCond = "";
        if($attendanceFromJoiningDate->attendanceFromJoiningDate === '1'){
        $studenAttendanceDateCond = " AND vamu.attendance_date >= sa.studentJoindate";
        }
        if($attendanceFromJoiningDate->start_date){
            $studenAttendanceDateCond = " AND va.attendance_date >= '$attendanceFromJoiningDate->start_date'";
        }
          $cond = "";
          if ($request->attendanceDateTillDate) {
            $joinCond = " AND vamu.attendance_date <= '$request->attendanceDateTillDate";
          }
          if ($request->termId) {
            $cond = " AND sg.academic_term_id = '$request->termId";
          }
          $sql = "SELECT
                    concat(IFNULL(s.name,''),' ( ' ,IFNULL(s.code,''),' )') as subjectName,
                    s.id,
                    caps.id as academicPaperId,
                    CASE 
                    WHEN csats.academic_term_id = sg.academic_term_id THEN ''
                    ELSE c.id
                    END AS groupByConditionForFeCommunity,
                    -- SUM(if(va.id is not null, 1, 0)) as totalAttendance,
                    -- SUM(if(va.is_absent = 0 OR  va.grant_leave is not null, 1, 0)) as totalPresent,
                    -- ROUND(IFNULL((SUM(if(va.is_absent = 0 OR  va.grant_leave is not null, 1, 0))/ SUM(if(va.id is not null, 1, 0)))* 100, 0),2) AS percentage
                    COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time) AS totalAttendance,
                    COUNT(DISTINCT CASE WHEN va.is_blocked = 0 AND (va.is_absent = 0 OR va.grant_leave IS NOT NULL) THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS totalPresent,
                    ROUND(IFNULL((COUNT(DISTINCT CASE WHEN va.is_blocked = 0 AND (va.is_absent = 0 OR va.grant_leave IS NOT NULL) THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) / COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time))*100,0),2) AS percentage
                  FROM
                    cluster c
                  INNER JOIN cluster_groups_relations cg ON
                    cg.cluster_id = c.id
                  INNER JOIN `groups` sg ON
                    sg.id = cg.groups_id
                    INNER JOIN groups_relations gr ON
                      sg.id = gr.child_groups_id 
                  INNER JOIN `groups` bg ON
                      bg.id = gr.parent_groups_id  
                  INNER JOIN cm_academic_paper_subjects caps ON
                    caps.id = sg.paperSubjectId
                  INNER JOIN v4_ams_subject s ON
                    s.id = caps.ams_subject_id
                  INNER JOIN group_members gm ON
                    gm.groups_id = sg.id
                  INNER JOIN student_program_account spa ON
                    spa.id = gm.student_id AND bg.id = spa.current_batch_id
                  INNER JOIN studentaccount sa ON
                    sa.studentID = spa.student_id
                      --  ADDED CASES
                  INNER JOIN cm_academic_paper_subjects caps2 ON 
                    caps2.ams_subject_id = s.id
                  INNER JOIN cm_academic_paper cap ON 
                    cap.id = caps2.cm_academic_paper_id 
                  INNER JOIN cm_syllabus_academic_term_settings csats ON 
                    cap.cm_syllabus_academic_term_settings_id = csats.id 
                  INNER JOIN  `groups` sg2 ON 
                    sg2.paperSubjectId =  caps2.id AND sg.academic_term_id = sg2.academic_term_id 
                  INNER JOIN group_members gm2 ON 
                    gm2.groups_id = sg2.id AND gm2.student_id = spa.id
                  INNER JOIN cluster_groups_relations cgr ON 
                    cgr.groups_id = sg2.id
                  INNER JOIN cluster c2 ON 
                    c2.id = cgr.cluster_id  
                  --  END OF ADDED CASES
                  LEFT JOIN v4_attendance_marked_user vamu ON
                    vamu.cluster_id = c2.id
                  LEFT join v4_timetable vt on vamu.time_table_id = vt.id and vt.suspended = '0'
                  LEFT JOIN v4_attendance va ON
                    va.v4_attendance_marked_user_table_id = vamu.id
                    and va.student_id = sa.studentID $joinCond $studenAttendanceDateCond
                  where
                    1 = 1  and gm.academic_status in ('COMPLETED','ACTIVE')       $cond
                    and sa.studentID = '$request->studentId'
                  ";
          $sql .= "GROUP BY  s.id,
                         csats.academic_term_id,
                         groupByConditionForFeCommunity
                    ORDER BY s.code  ";
          $attendanceDetails = $this->executeQueryForList($sql, $this->mapper[AttendanceServiceMapper::GET_SUBJECT_ATTENDANCE_DETAILS]);
          $header = [
             [
                 "key" => "subjectName",
                 "label" => "Subject",
             ],
             [
                 "key" => "percentage",
                 "label" => "Percentage",
             ],
         ];
          $response = new stdClass();
          $response->headers = $header;
          $response->data = $attendanceDetails;
        } catch (\Throwable $e) {
          throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $response;
    }
    public function getAttendanceDetailsApi($studentID, $semID = null,$attClosingDate = null)
    {
        try{
                $studentID = $this->realEscapeString($studentID);
                $semID = $this->realEscapeString($semID);
                $attClosingDate = $this->realEscapeString($attClosingDate);
        
                //getting attendance rule
        
                $studentDetail = StudentService::getInstance()->getStudentDetailsById($studentID);
        
                if(!empty($semID))
                {
                    $attendanceRules = $this->getAttendanceRule($studentDetail->batchID, $semID);
                    if(!$attendanceRules)
                    {
                        throw new ProfessionalException(ProfessionalException::INVALID_SEMESTER_ID, "Attendance rule not found ");
                    }
                }
                else
                {
                    $attendanceRules = $this->getAttendanceRule($studentDetail->batchID, $studentDetail->semID);
                }
        
                $request = new stdClass();
                $request->ruleBatchId = $studentDetail->batchID;
                $request->batchId = null;
                if($attendanceRules->dateOfjoining && (strtotime($studentDetail->studentJoindate) > strtotime($attendanceRules->classStartsFrom) ) && !empty($studentDetail->studentJoindate)){
                    $request->fromDate = $studentDetail->studentJoindate;
                }
                else{
                    $request->fromDate = $attendanceRules->classStartsFrom;
                }
                $request->toDate  = $attClosingDate ? $attClosingDate :$attendanceRules->classEnds;
                $request->studentId = $studentID;
                if(!empty($semID)) {
                    $request->ruleSemId = $semID;
                } else {
                    $request->ruleSemId = $studentDetail->semID;
                }
                $request->mustTakeAttendanceRule = true;
                $request->semId = null;
                $request->attendanceRules = $attendanceRules;
                $request->studentJoindate = $studentDetail->studentJoindate;
        
        
        
                //daywise
                $dayWiseStudentAttendanceDetails = $this->getStudentsDaywiseAttendance($request);
        
                //hourwise
                $hourWiseStudentAttendanceDetails = $this->getStudentsHourwiseAttendanceForApi($request);
        
        
                $attendance = new stdClass();
                $attendance->dayWise = $dayWiseStudentAttendanceDetails;
                $attendance->hourWise = $hourWiseStudentAttendanceDetails;
        
                // return json_decode($attendance);
                return $attendance;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getStudentsDaywiseAttendance($request){
        try{
            $studentID = $_SESSION['studentID']?$_SESSION['studentID']:$request->studentId;
            $joiningDate = $request->studentJoindate;
            //handling late comer using attendance rule
            $attendanceRule = $request->attendanceRules;
            $dateOfjoining = $attendanceRule->dateOfjoining;
            if ($dateOfjoining) {
                if (strtotime($joiningDate) > strtotime($request->fromDate)) {
                    $hisfromDate = $joiningDate;
                } else {
                    $hisfromDate = $request->fromDate;
                }
            } else {
                $hisfromDate = $request->fromDate;
            }
            $morninghours = $request->attendanceRules->morninghours;
            $total_attendance = 0;
            $total_workingdays = 0;
            $halfday_absent = 0;
            $fullday_absent = 0;
            $request = $this->realEscapeObject($request);
            $sql = "SELECT DISTINCT(attendanceDate) from attendance where semID=\"$request->ruleSemId\" and batchID=\"$request->ruleBatchId\" and attendanceDate BETWEEN '$hisfromDate' AND '$request->toDate' ORDER BY attendanceDate ";
            $dates = $this->executeQueryForList($sql);
            $finalDates = [];
            GLOBAL $ATTENDANCE_HOURS;
            if($dates)
            {
                foreach($dates as $dat)
                {
                    $count = 0;
                    $isAvoided = 0;
                    $morning_session = true;
                    $afternoon_session = true;
                    $attendance_today = 0;
                    $date = $dat->attendanceDate;
                    $attended = 0;
                    $block_sql = "SELECT t1.hour, t1.isAbsent, t1.isBlocked from attendance t1 where  t1.attendanceDate='$date' and t1.batchID=\"$request->ruleBatchId\"  and t1.semID=\"$request->ruleSemId\" and t1.studentID=$studentID  ORDER BY t1.hour";
                    $status = $this->executeQueryForList($block_sql);
                    foreach ($status as $key => $st) {
                            $count = $count + 1;
                            if($st->isAbsent == 1 || $st->isBlocked == 1)
                            {
                                if($st->hour <= $morninghours)
                                {
                                    $morning_session = false;
                                }
                                else{
                                    $afternoon_session = false;
                                }
                                $isAvoided = $isAvoided + 1;
                            }
                    }
                   
                    //halfday(FN) completed successfully
                    if(count($status) > 0 && $morning_session)
                    {
                        $attendance_today = $attendance_today + .5;
                    }
                    //halfday(AN) completed successfully
                    if(count($status) > 0 && $afternoon_session)
                    {
                        $attendance_today = $attendance_today + .5;
                    }
                    if(count($status) > 0 )
                    {
                        //incrementing total working day
                        $total_workingdays++;
                    }
                    if($attendance_today == .5)
                    {
                        //logging halfday absents
                        $halfday_absent++;
                    }
                    if(count($status) > 0  && $attendance_today == 0)
                    {
                        //fullday attendance taken but the kid stayed outside
                        $fullday_absent++;
                    }
                    if($status)
                    {
                        $attended = 1;
                        if ($status->isAbsent == 1 || $status->isBlocked == 1) {
                            if ($i <= $morninghours) {
                                $morning_session = false;
                            } else {
                                $afternoon_session = false;
                            }
                        }
                        
                    }
                    if($status)
                    {
                        $ruleConverted = new stdClass();
                        $ruleConverted->date = $dat->attendanceDate;
                        $ruleConverted->attendance_today = $attendance_today ? $attendance_today : 0;
                        $finalDates[$dat->attendanceDate] = $ruleConverted;
                    }
                    
                    
                }
                
            }
            $finalCount = 0;
            $attendanceHolder = 0;
            foreach($finalDates as $date)
            {
                $finalCount++;
                $attendanceHolder = $attendanceHolder + $date->attendance_today;
            }
            if($attendanceHolder)
            {
                $result = (float)($attendanceHolder/$finalCount) * 100;
            }
            else{
                $result = 0;
            }
            $response = new stdClass();
            $response->headers = [];
            
            $header = new stdClass();
            $header->key = "totalNoOfWorkingDays";
            $header->label = "Total Number of Working Days";
            $response->headers[] = $header;
            $header = new stdClass();
            $header->key = "totalAttendedWorkingDaysInASemester";
            $header->label = "Total Attended Working Days In a Semester";
            $response->headers[] = $header;
            $header = new stdClass();
            $header->key = "currentDayWiseAttendancePercentageInASemester";
            $header->label = "Current Day Wise Attendance Percentage In a Semester";
            $response->headers[] = $header;
           $response->data = [];
           $dataObject = new stdClass();
            $dataObject->totalNoOfWorkingDays = $finalCount;
            $dataObject->totalAttendedWorkingDaysInASemester = $attendanceHolder;
            $dataObject->currentDayWiseAttendancePercentageInASemester = $result;
            
            $response->data[] = $dataObject;
            // $json = json_encode($response);
            return $response;
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getStudentsHourwiseAttendanceForApi($request){
        $request = $this->realEscapeObject($request);
        
        $subColumns = ["st.studentID","st.studentName","st.studentAccount","st.rollNo","at.attendanceDate"];
        $columns = [];
        
        if(empty($request->attendanceRules))
        {
            if($request->ruleBatchId && $request->ruleSemId){
                $attendanceRules = $this->getAttendanceRule($request->ruleBatchId, $request->ruleSemId);
            }
        }
        else
        {
            $attendanceRules = $request->attendanceRules;
        }
        $attendanceRules->classStartsFrom = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
        $attendanceRules->classEnds = date('Y-m-d', strtotime($attendanceRules->classEnds));
        //batchID,semID,dateOfjoining,morninghours,classStartsFrom,classEnds,isActive,halfdayHourCount,fulldayHourCount
        
        if($request->mustTakeAttendanceRule){
            if(empty($attendanceRules))
            {
                throw new ProfessionalException(ProfessionalException::INVALID_REQUEST, "Attendance rules not defined");
            }
        }
        $fromDateRule = !empty($attendanceRules->classStartsFrom) ? new \DateTime($attendanceRules->classStartsFrom) : null;
        $toDateRule = !empty($attendanceRules->classEnds) ? new \DateTime($attendanceRules->classEnds) : null;
        $request->fromDate = $request->fromDate?date('Y-m-d', strtotime($request->fromDate)):null;
        $request->toDate = $request->toDate?date('Y-m-d', strtotime($request->toDate)):date('Y-m-d');
        //if $fromDateRule is valid, $fromDate is smaller than $fromDateRule and if attendance rule is activate then take $fromDateRule as $fromDate
        if ($fromDateRule && strtotime($attendanceRules->classStartsFrom) > 0 && $attendanceRules->isActive) {
            if(empty($request->fromDate)){
                $request->fromDate = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
            }
            else if (CommonUtil::isFromDateSameOrBeforeToDate($request->fromDate, $attendanceRules->classStartsFrom)) {
                $request->fromDate = date('Y-m-d', strtotime($attendanceRules->classStartsFrom));
            }
        }
        //if $toDateRule is valid, $todate is greater than $toDateRule and if attendance rule is activate then take $toDateRule as $todate
        if ($toDateRule && strtotime($attendanceRules->classEnds) > 0 && $attendanceRules->isActive) {
            if(empty($request->toDate)){
                $request->toDate = date('Y-m-d', strtotime($attendanceRules->classEnds));
            }
            else if (CommonUtil::isFromDateSameOrBeforeToDate($attendanceRules->classEnds, $request->toDate)) {
                $request->toDate = date('Y-m-d', strtotime($attendanceRules->classEnds));
            }
        }
        
        if((int)$attendanceRules->halfdayHourCount && (int)$attendanceRules->fulldayHourCount){
            $subColumns = array_merge($subColumns,["IF(SUM(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->halfdayHourCount.",'.5',0) AS present_evening","IF(sum(IF((find_in_set(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->fulldayHourCount.",'.5',0) AS present_morning","IF(sum(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->halfdayHourCount.",'.5',0) + IF(sum(IF((FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked <> 1),1,0)) >= ".(int)$attendanceRules->fulldayHourCount.",'.5',0) AS sum_of_session"]);
        }else{
            $morninghours = (int)$attendanceRules->morninghours?$attendanceRules->morninghours:$request->morninghours;
            $subColumns = array_merge($subColumns,["IF(FIND_IN_SET('1',group_concat(IF(at.hour <= ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS present_morning","IF(FIND_IN_SET('1',group_concat(IF(at.hour > ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS present_evening","IF(FIND_IN_SET('1',group_concat(IF(at.hour <= ".(int)$morninghours.",at.isAbsent,null))),0,'.5') + IF(FIND_IN_SET('1',group_concat(if(at.hour > ".(int)$morninghours.",at.isAbsent,null))),0,'.5') AS sum_of_session"]);
        }
        $dlWorkFlow = CommonService::getInstance()->getSettings(SettingsConstents::LEAVE_MANAGEMENT, SettingsConstents::ENABLE_LEAVE_WORKFLOW);
        // $dlHourCount = $dlWorkFlow?"SUM(IF(at.isAbsent = 2 AND dl.dlrName is not null,1,0)) AS dl_hourIds":"SUM(IF(at.isAbsent = 2,1,0)) AS dl_hourIds";
        $dlHourCount = "SUM(IF(at.isAbsent = 2,1,0)) AS dl_hourIds";
        $subColumns = array_merge($subColumns,["COUNT(at.hour) AS hourIds","SUM(IF(FIND_IN_SET(at.isAbsent,'0,2') AND at.isBlocked != 1,1,0)) AS present_hourIds","SUM(IF(FIND_IN_SET(at.isAbsent,'0') AND at.isBlocked != 1,1,0)) AS attended_hourIds",$dlHourCount,"SUM(IF(at.isAbsent = 1,1,0)) AS isAbsent"]);
        
        $where = [];
        $request->batchId?$where[] = "b.batchID = '".$request->batchId."'":null; 
        $request->studentId?$where[] = "st.studentID = '".$request->studentId."'":null; 
        $request->semId?$where[] = "at.semID = '".$request->semId."'":null; 
        $request->studentIds?$where[] = "st.studentID in (".implode(',',$request->studentIds).")":null; 
        $request->currentSem?$where[] = "b.semID = at.semID":null; 
        $request->sbsId?$where[] = "sbs.sbsID = '".$request->sbsId."'":null; 
        
        if($request->fromDate && $request->toDate){
            // Adding date conditions 
            $where[] = $attendanceRules->dateOfjoining ?"CASE WHEN st.studentJoindate IS NOT NULL AND st.studentJoindate <> '0000-00-00' AND st.studentJoindate > '".$request->fromDate."' THEN at.attendanceDate BETWEEN st.studentJoindate AND '".$request->toDate."' ELSE at.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."' END":"at.attendanceDate BETWEEN '".$request->fromDate."' AND '".$request->toDate."'";
            $subColumns = array_merge($subColumns,["IF(st.studentJoindate IS NOT NULL AND st.studentJoindate <> '0000-00-00' AND st.studentJoindate > '".$request->fromDate."',st.studentJoindate,'".$request->fromDate."') AS fromDate","'".$request->toDate."' AS toDate"]);
        }else{
            $subColumns = array_merge($subColumns,["null AS fromDate","null AS toDate"]);
        }
        $joinSbs = "INNER JOIN sbs_relation sbs ON sbs.sbsID = at.sbsID";
        if($request->subjectId){
            $joinSbs = "INNER JOIN sbs_relation sbs ON sbs.sbsID = at.sbsID AND b.batchID = sbs.batchID";
            $where[] = "sbs.subjectID = '$request->subjectId'";
        }
        
        $sql = 
            "SELECT studentID,studentName,studentAccount,rollNo,
            COUNT(attendanceDate) AS date_count,
            SUM(IF(present_morning OR present_evening,1,0)) AS present_days,
            ROUND((SUM(IF(present_morning OR present_evening,1,0))/count(attendanceDate))*100,2) AS present_days_percentage,
            SUM(sum_of_session) AS session_present_count,
            ROUND((sum(sum_of_session)/COUNT(attendanceDate))*100,2) AS percentage_of_session,
            COUNT(attendanceDate) - SUM(IF((present_morning = .5 and present_evening = 0) OR (present_morning = 0 and present_evening = .5),0,1)) AS half_day,
            COUNT(attendanceDate) - SUM(IF(present_morning = 0 AND present_evening = 0,0,1)) AS full_day,
            SUM(hourIds) AS hourCount,
            SUM(present_hourIds) AS present_hour_count,
            SUM(attended_hourIds) AS attended_hour_count, 
            SUM(isAbsent) AS absent_hour_count, 
            SUM(dl_hourIds) AS dl_hour_count,
            ROUND((sum(present_hourIds)/SUM(hourIds))*100,2) AS hour_percentage,
            GROUP_CONCAT(distinct fromDate) as fromDate,
            GROUP_CONCAT(distinct toDate) as toDate
            FROM (
                SELECT  ".implode(',', $subColumns)."
                FROM studentaccount st 
                    INNER JOIN attendance at ON at.studentID = st.studentID
                    INNER JOIN batches b ON b.batchID = st.batchID
                    ".$joinSbs."
                    LEFT JOIN duty_leave_remarks dl on dl.dlrId = at.dlrId and dlrName is not null and at.isAbsent = 2
                    " . ($where ? " WHERE " . implode(' AND ', $where) : "") . "
                GROUP BY st.studentID, at.attendanceDate
                ORDER BY at.hour
            ) AS temp 
            GROUP BY studentID ORDER BY rollNo;";
        try{
            $result =  $this->executeQueryForObject($sql);
            $response = new stdClass();
            $response->headers = [];
            
            $header = new stdClass();
            $header->key = "totalNoOfWorkingHours";
            $header->label = "Total Number of Working Hours";
            $response->headers[] = $header;
            $header = new stdClass();
            $header->key = "totalAttendedWorkingHoursInASemester";
            $header->label = "Total Attended Working Hours In a Semester";
            $response->headers[] = $header;
            $header = new stdClass();
            $header->key = "currentHourWiseAttendancePercentageInASemester";
            $header->label = "Current Hour Wise Attendance Percentage In a Semester";
            $response->headers[] = $header;
           $response->data = [];
           $dataObject = new stdClass();
            $dataObject->totalNoOfWorkingHours = $result->hourCount;
            $dataObject->totalAttendedWorkingHoursInASemester = $result->attended_hour_count;
            $dataObject->currentHourWiseAttendancePercentageInASemester = $result->hour_percentage;
            
            $response->data[] = $dataObject;
            // $json = json_encode($response);
            return $response;
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getHoursDetailsFromAttendanceOfStudent($date,$studentID,$detailed = false)
    {
        try
        {
            $date = $this->realEscapeString($date);
            $date = strtotime($date);
            $newDate = date('Y-m-d', $date);
            $studentID = $this->realEscapeString($studentID);
            if($detailed)
            {
                $sql = "SELECT DISTINCT hour,isAbsent from attendance a WHERE a.attendanceDate = '$newDate' and studentID = $studentID";
            }
            else{
                $sql = "SELECT DISTINCT hour from attendance a WHERE a.attendanceDate = '$newDate' and studentID = $studentID";
            }
            return $this->executeQueryForList($sql);
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getStudentAttendanceDetailsByStudent($payload){
        try{
            $payload = $this->realEscapeObject($payload);
            $payload->date = strtotime($payload->date);
            $payload->date = date('Y-m-d', $payload->date);
            $sql = "SELECT id from attendance WHERE attendanceDate = '$payload->date' and hour = $payload->hour and studentID = $payload->studentId";
            return $this->executeQueryForObject($sql) ? true : false;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function giveAttendanceForStudent($payload)
    {
        try{
            $payload = $this->realEscapeObject($payload);
            $sql = "UPDATE attendance SET isAbsent = 0 WHERE attendanceDate = '$payload->date' and hour = $payload->hour and studentID = $payload->studentId";
            $this->executeQuery($sql);
            return true;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function CheckForSubjectPlanner($date, $hour, $subjectID, $batchID = "",$psID = "")
    {
        try{
            $staffID = $_SESSION['staffID'];
            $date = $this->realEscapeString($date);
            $hour = $this->realEscapeString($hour);
            $subjectID = $this->realEscapeString($subjectID);
            $batchID = $this->realEscapeString($batchID);
            $subbatchID = $this->realEscapeString($subbatchID);
            $unixDate = strtotime($date);
            if($psID)
            {
                $sql = "SELECT 
                                 spp.topicID,sr.sbsID,spp.date,spp.hour
                                FROM subjectplan_ps_proposed spp 
                                inner join pseudosubjects_sbs ps on ps.pseudosubjectID = spp.pssId 
                                inner join sbs_relation sr on sr.sbsID = ps.sbsID 
                                WHERE spp.`date` ='$unixDate' and spp.`hour` ='$hour' and sr.staffID ='$staffID' and spp.pssId ='$psID' ORDER BY spp.`date` DESC;";
                    
            }
            else{
                
                $sql = "SELECT
                            sp.topicID,sr.sbsID,sp.date,sp.hour
                            from
                                subjectplan_proposed sp
                            inner join sbs_relation sr on
                                sr.sbsID = sp.sbsID
                                WHERE `date` = '$unixDate' and `hour` ='$hour' and sr.staffID ='$staffID' and sr.subjectID ='$subjectID' and sr.batchID ='$batchID' ORDER BY sp.`date` DESC";
                
            }
           
            
            
            return $this->executeQueryForList($sql);
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function CheckForSubjectPlannerInActualPlan($sbsID,$attendanceDate,$hour,$pseudoSubjectId = '')
    {
        try{
            $flagForFirstEntry = "SELECT count(attendanceDate) as attendanceCount FROM attendance_confirm ac WHERE sbsID in ($sbsID)";
            $attendanceCount = $this->executeQueryForObject($flagForFirstEntry);
            $isFirstEntry = $attendanceCount->attendanceCount  == "0" ? true : false;
            if($isFirstEntry)
            {
                return true;
            }
            $topicID = $this->realEscapeString($topicID);
            $pseudoSubjectId = $this->realEscapeString($pseudoSubjectId);
            if($pseudoSubjectId)
            {
                $sql = "SELECT topicID,date,hour,pssId from subjectplan_ps_proposed WHERE pssId = '$pseudoSubjectId' and (date <= $attendanceDate and hour < $hour) ORDER BY date DESC,hour DESC";
                $proposedData =  $this->executeQueryForList($sql);
                foreach ($proposedData as $key => $plan) {
                    $checkForActualPlans = "SELECT * FROM ps_subjectplan  WHERE pssId = $plan->pssId and date = $plan->date and hour = $plan->hour ";
                    $foundActualPlanner = $this->executeQueryForObject($checkForActualPlans);
                    if(!$foundActualPlanner)
                    {
                        return false;
                    }
                }
                return true;
            }
            else{
                $sql = "SELECT topicID,date,hour,sbsID  from subjectplan_proposed sp WHERE sbsID in ($sbsID) and (date <= $attendanceDate and hour < $hour) ORDER BY date DESC, hour DESC";
                $proposedData =  $this->executeQueryForList($sql);
                foreach ($proposedData as $key => $plan) {
                    $checkForActualPlans = "SELECT * FROM subjectplan WHERE sbsID in ($sbsID) and date = $plan->date and hour = $plan->hour ";
                    $foundActualPlanner = $this->executeQueryForObject($checkForActualPlans);
                    if(!$foundActualPlanner)
                    {
                        return false;
                    }
                }
                return true;
                
            }
     
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getAttendanceExistingOrNot($date,$hour)
    {
        try{
            $date = $this->realEscapeString($date);
            $hour = $this->realEscapeString($hour);
            $studentID = $_SESSION['studentID'];
            $sql = "SELECT id from attendance WHERE attendanceDate = '$date' and hour in ($hour) and studentID = $studentID and isAbsent = 0 ";
            $isPresent =  $this->executeQueryForObject($sql) ? true : false;
            return $isPresent;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function blockAttendanceForStudent($studentID,$date,$hours)
    {
        $studentID = $this->realEscapeString($studentID);
        $date = $this->realEscapeString($date);
        $hours = $this->realEscapeString($hours);
        $staffID =  $_SESSION['adminID'] ? $_SESSION['adminID'] : $_SESSION['staffID'];
        
        try{
            $sql = "INSERT INTO attendance_blocked_students(studentId,date,hours) VALUES($studentID,'$date','$hours')";
            $sqlLogInsert = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($studentID,'$date','$hours','INSERT','FEE_DUE','$staffID')";
            $this->executeQuery($sql);
            $this->executeQuery($sqlLogInsert);
            return true;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getBlockedDetailsByStudentID($studentID)
    {
        try{
            $studentID = $this->realEscapeString($studentID);
            $sql = "SELECT studentId ,GROUP_CONCAT(`date`) as dates,hours  from attendance_blocked_students WHERE studentId =$studentID GROUP BY studentId ORDER BY date ASC";
            return $this->executeQueryForObject($sql);
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function removeBlockAttendance($studentID)
    {
        try{
            $studentID = $this->realEscapeString($studentID);
            $staffID =  $_SESSION['adminID'] ? $_SESSION['adminID'] : $_SESSION['staffID'];
            $sql = "DELETE FROM attendance_blocked_students WHERE studentId =$studentID";
            $sqlUpdateToBlocked = "SELECT id from attendance WHERE studentID = $studentID";
            $attendances = $this->executeQueryForList($sqlUpdateToBlocked);
            foreach ($attendances as $key => $att) {
                $updateBlocksql = "UPDATE attendance SET isBlocked = 1 WHERE id = $att->id";
                $this->executeQuery($updateBlocksql);
            }
            $sqlLogInsert = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($studentID,'$date','$hours','DELETE','FEE_DUE','$staffID')";
            $this->executeQuery($sql);
            $this->executeQuery($sqlLogInsert);
            return true;
   
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function MultiBlockAttendance($studentIDs,$block,$fromDate,$toDate,$selectedHours)
    {
        try{
            $studentIDs = $this->realEscapeArray($studentIDs);
            $fromDate = $this->realEscapeString($fromDate);
            $toDate = $this->realEscapeString($toDate);
            $selectedHours = $this->realEscapeString($selectedHours);
            $staffID =  $_SESSION['adminID'] ? $_SESSION['adminID'] : $_SESSION['staffID'];
            
            if($block)
            {
                $start = new \DateTime($fromDate);
                $end = new \DateTime($toDate);
                $interval = new \DateInterval('P1D');
                $end->add($interval);
                $date_period = new \DatePeriod($start, $interval, $end);
                $dates = [];
                foreach ($date_period as $date) {
                    $dates[] = $date->format('Y-m-d');
                }
                foreach ($dates as $date) {
                    foreach ($studentIDs as  $student) {
                        $sqlCheck = "SELECT id from attendance_blocked_students WHERE studentId = $student and date = '$date' and hours = '$selectedHours'";
                        $exists = $this->executeQueryForObject($sqlCheck);
                        if(!$exists->id)
                        {
                            $sql = "INSERT  INTO attendance_blocked_students(studentId,date,hours) VALUES($student,'$date','$selectedHours')";
                            $sqlLogInsert = "INSERT INTO attendance_blocking_log(studentId,date,hours,action,context,staffID) VALUES($student,'$date','$selectedHours','INSERT','FEE_DUE','$staffID')";
                            $this->executeQuery($sql);
                            $this->executeQuery($sqlLogInsert);
                        }
                    }
                }
            }
            else{
                foreach ($studentIDs as  $student) {
                    $this->removeBlockAttendance($student);
                }
            }
            return true;
        }catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    
    
    /*
    * Function to get the attendance details   and dl details of a student aganist the current semester
    * @param $studentID
    * @return $attendance
    */
    
    public function getDutyLeaveDetailsByStudentID($studentId, $leaveAppId){
        
        try{
            $response = new stdClass();
            
            $checkSettings = CommonService::getInstance()->getSettings(SettingsConstents::ATTENDANCE_SETTINGS, SettingsConstents::SHOW_DUTY_LEAVE_DETAILS_IN_STUDENTLEAVE_MANAGEMENT);
            $settingsData =  json_decode($checkSettings);
            if($settingsData->showDlDeatailsInStudentLeaveManagement === '0'){
                $response->showDlAdvanceDetails = false;
                return $response;
            }
            
            $query = "SELECT  vaar.start_date , vaar.end_date from v4_ams_attendance_rules vaar
                    INNER JOIN `groups` g ON g.id = vaar.batch_groups_id
                    INNER JOIN student_program_account spa ON spa.current_batch_id = g.id
                    INNER JOIN studentaccount s ON s.studentID = spa.student_id
                    WHERE 1=1 AND g.academic_term_id = vaar.academic_term_id  ";
    
            if($studentId) {
              $query .= " AND s.studentID   = '$studentId'";
            }
             
            $dateDetails = $this->executeQueryForObject($query);
            
            
            if(!$dateDetails){
                $response->showDlAdvanceDetails = false;
                return $response;
            }
            
            
            // TOPTAL APPLIED DL
            
            // $totalSql = "SELECT 
            //                 student_Id ,
            //                 SUM((LENGTH(session_key) - LENGTH(REPLACE(session_key, ',', '')) + 1) * noof_days) AS total_applied_hour
            //             FROM  student_leave_application sla
            //             WHERE sla.student_Id = '$studentId'
            //             AND sla.start_date >= '$dateDetails->start_date'  AND sla.end_date <= '$dateDetails->end_date'
            //             GROUP BY student_Id ";
                        
            // $totalAppliedDL = $this->executeQueryForObject($totalSql);
            // $response->totalAppliedDL = $totalAppliedDL->total_applied_hour;
            
            // ATTENDANCE MARKED AGANIST THE APPLIED LEAVE AND GRANTED DL
            // CURRNETLY ALL APPROVED DL ARE TAKING  NO NEED IT CHECK TROUGH IT  SO WE CAN TAKE FROM THE BELOW QUERY IF IT IS AGANIST THE APPLIED LEAVE THEN WE CAN USE THIS
            
            // $attendanceSql = "WITH SplitSessions AS (
            //                         SELECT 
            //                             sla.id,
            //                             sla.noof_days,
            //                             sk.value AS session_key,
            //                             sla.start_date,
            //                             sla.end_date,
            //                             sla.student_id
            //                         FROM student_leave_application sla
            //                         JOIN JSON_TABLE(
            //                                 CONCAT('[\"', REPLACE(sla.session_key, ',', '\",\"'), '\"]'),
            //                                 '$[*]' COLUMNS (value INT PATH '$')
            //                         ) sk
            //                         WHERE sla.student_id = '$studentId'
            //                              AND sla.start_date >= '$dateDetails->start_date'  
            //                              AND sla.end_date <= '$dateDetails->end_date'
            //                     )
            //                     SELECT COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time) as attendanceMarked FROM SplitSessions ss
            //                     INNER JOIN v4_attendance va ON va.student_id = ss.student_id AND va.attendance_date  BETWEEN ss.start_date AND ss.end_date
            //                     INNER JOIN v4_attendance_marked_user vamu ON vamu.id = va.v4_attendance_marked_user_table_id  AND vamu.marked_hour  = ss.session_key
            //                     WHERE va.attendance_date BETWEEN '$dateDetails->start_date' AND '$dateDetails->end_date'
            //                     AND va.grant_leave IS NOT NULL
            //                     GROUP BY va.student_id";
                                
            // $attendanceMarkedDlDetails = $this->executeQueryForObject($attendanceSql);
            // $response->attendanceMarkedAganistAppliedDl = $attendanceMarkedDlDetails->attendanceMarked;
            
            // DL APPLICABLE AGANIST THE CURRENT LEAVE APPLICATION
            $attendanceDlApprovedSql = "WITH SplitSessions AS (
                                        SELECT 
                                            sla.id,
                                            sla.noof_days,
                                            sk.value AS session_key,
                                            sla.start_date,
                                            sla.end_date,
                                            sla.student_id
                                        FROM student_leave_application sla
                                        JOIN JSON_TABLE(
                                            CONCAT('[\"', REPLACE(sla.session_key, ',', '\",\"'), '\"]'),
                                            '$[*]' COLUMNS (value INT PATH '$')
                                        ) sk
                                        WHERE sla.student_id = '$studentId'
                                             AND sla.start_date >= '$dateDetails->start_date'  
                                             AND sla.end_date <= '$dateDetails->end_date'
                                            --  AND sla.status = 'APPROVED'
                                             AND sla.id = '$leaveAppId'
                                        
                                    )
                                    SELECT count(va.student_id) as attendanceMarked FROM SplitSessions ss
                                    INNER JOIN v4_attendance va ON va.student_id = ss.student_id  AND va.attendance_date  BETWEEN ss.start_date AND ss.end_date
                                    INNER JOIN v4_attendance_marked_user vamu ON vamu.id = va.v4_attendance_marked_user_table_id  AND vamu.marked_hour  = ss.session_key
                                    WHERE va.attendance_date BETWEEN '$dateDetails->start_date' AND '$dateDetails->end_date'
                                    AND va.is_absent = 1
                                    GROUP BY va.student_id";
                                    
            $attendanceMarkedDlApprovedDetails = $this->executeQueryForObject($attendanceDlApprovedSql);
            $response->applicableAganistCurrentApplication = $attendanceMarkedDlApprovedDetails->attendanceMarked ? $attendanceMarkedDlApprovedDetails->attendanceMarked : 0;
            
            // TO FIGURE OUT THE ATTENDANCE PERCENTAGE AND IF IT IS LESS THAN THE CUT OFF THEN NEED TO FING HOW MANY HOURS IS NEEDED TO BE MARKED
            
            $attendancePercentageSql = "SELECT  
                                            COUNT(DISTINCT CASE WHEN ( va.grant_leave IS NOT NULL) THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS availedGrantLeave,
                                            COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time) AS totalAttendance, 
                                            COUNT(DISTINCT CASE WHEN (va.is_absent = 0 OR va.grant_leave IS NOT NULL) THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) AS totalPresent,
                                            ROUND(IFNULL((COUNT(DISTINCT CASE WHEN (va.is_absent = 0 OR va.grant_leave IS NOT NULL) THEN CONCAT(va.student_id, va.attendance_date, va.start_time, va.end_time) END) / COUNT(DISTINCT va.student_id, va.attendance_date, va.start_time, va.end_time))*100,0),2) AS attendancePercentage
                                           FROM 
                                                studentaccount s 
                                            INNER JOIN student_program_account spa ON spa.student_id = s.studentID 
                                            --  COMMENTED AND ADDED THE CONDITION OF BATCH LOG TO GET THE PREVIOUS SEMESTER ATTENDANCE
                                            INNER JOIN student_program_batch_log spbl ON 
                                            spbl.program_student_id = spa.id AND  
                                            -- spbl.term_id = sg.academic_term_id AND 
                                            spbl.properties->> '$.academicStatus' IN ('ACTIVE', 'COMPLETED')
                                            INNER JOIN  `groups` g ON g.id = spbl.batch_group_id  
                                            INNER JOIN groups_relations gr ON gr.parent_groups_id = g.id 
                                            INNER JOIN `groups` sg ON sg.id = gr.child_groups_id 
                                            INNER JOIN group_members gm ON gm.groups_id  = sg.id AND gm.student_id = spa.id AND gm.academic_status = 'ACTIVE'
                                            INNER JOIN cm_academic_paper_subjects caps ON caps.id = sg.paperSubjectId
                                            INNER JOIN v4_ams_subject vas ON vas.id = caps.ams_subject_id 
                                            INNER JOIN cm_academic_paper_subjects caps2 ON caps2.ams_subject_id = vas.id 
                                            INNER JOIN `groups` sg2 ON sg2.paperSubjectId = caps2.id AND sg2.academic_term_id = sg.academic_term_id
                                            INNER JOIN groups_relations gr2 ON gr2.child_groups_id = sg2.id
                                            INNER JOIN `groups` g2 ON g2.id = gr2.parent_groups_id AND g2.properties ->>'$.startYear' = g.properties->>'$.startYear'
                                            INNER JOIN group_members gm2 ON gm2.groups_id = sg2.id AND gm2.student_id = spa.id 
                                            INNER JOIN cluster_groups_relations cgr ON cgr.groups_id = sg2.id 
                                            INNER JOIN cluster c ON c.id = cgr.cluster_id 
                                            INNER JOIN  v4_attendance va ON va.cluster_id = c.id AND s.studentID = va.student_id 
                                         WHERE va.attendance_date BETWEEN '$dateDetails->start_date' AND '$dateDetails->end_date'
                                         AND va.student_id = '$studentId'
                                         AND  spa.current_batch_id = g2.id
                                         AND sg2.academic_term_id = spa.current_term_id 
                                         GROUP BY va.student_id";
            
            $attendancePercentageDetails = $this->executeQueryForObject($attendancePercentageSql);
            if($attendancePercentageDetails->attendancePercentage < 75){
                // Calculate how many more total present hours needed to reach 75% attendance
                $requiredPercentage = $settingsData->attendanceCutOffPercentage;
                $currentPercentage = $attendancePercentageDetails->attendancePercentage;
                $totalAttendance = $attendancePercentageDetails->totalAttendance;
                $totalPresent = $attendancePercentageDetails->totalPresent;
                // Formula to calculate hours needed:
                // (required_percentage * total_attendance) / 100 = required_present_hours
                $requiredPresentHours = ceil(($requiredPercentage * $totalAttendance) / 100);
                $moreAttendanceNeeded = $requiredPresentHours - $totalPresent;
                // Only set this if more hours are needed
                if ($moreAttendanceNeeded > 0) {
                    $response->moreAttendanceNeeded = $moreAttendanceNeeded;
                    $response->currentAttendancePercentage = $currentPercentage;
                    $response->requiredAttendancePercentage = $requiredPercentage;
                    $response->actualAttendancePercentage = $currentPercentage;
                    $response->totalAttendance = $totalAttendance;
                    $response->totalPresent = $totalPresent;
                    $response->attendanceMarkedAganistAppliedDl = $attendancePercentageDetails->availedGrantLeave;
                }
            }
            else{
                $response->moreAttendanceNeeded = 0;
                $response->currentAttendancePercentage = $attendancePercentageDetails->attendancePercentage;
                $response->requiredAttendancePercentage = $settingsData->attendanceCutOffPercentage;
                $response->actualAttendancePercentage = $attendancePercentageDetails->attendancePercentage;
                $response->totalAttendance = $attendancePercentageDetails->totalAttendance;
                $response->totalPresent = $attendancePercentageDetails->totalPresent;
                $response->attendanceMarkedAganistAppliedDl = $attendancePercentageDetails->availedGrantLeave;
            }
            $response->showDlAdvanceDetails = true;
            return $response;
            
      
        }
        catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        
    }
    
}