TTi18n::gettext( 'Unscheduled Absence' ), 'S2' => TTi18n::gettext( 'Not Scheduled' ), 'S3' => TTi18n::gettext( 'In Early' ), 'S4' => TTi18n::gettext( 'In Late' ), 'S5' => TTi18n::gettext( 'Out Early' ), 'S6' => TTi18n::gettext( 'Out Late' ), //'SS' => TTi18n::gettext('In Early (Level 2)'), //Allow for 2 or 3 levels of schedule exceptions. //'ST' => TTi18n::gettext('In Late (Level 2)'), //'SU' => TTi18n::gettext('Out Early (Level 2)'), //'SV' => TTi18n::gettext('Out Late (Level 2)'), //'SW' => TTi18n::gettext('In Early (Level 3)'), //Allow for 2 or 3 levels of schedule exceptions. //'SX' => TTi18n::gettext('In Late (Level 3)'), //'SY' => TTi18n::gettext('Out Early (Level 3)'), //'SZ' => TTi18n::gettext('Out Late (Level 3)'), 'S7' => TTi18n::gettext( 'Over Daily Scheduled Time' ), 'S8' => TTi18n::gettext( 'Under Daily Scheduled Time' ), 'S9' => TTi18n::gettext( 'Over Weekly Scheduled Time' ), //'SA' => TTi18n::gettext('Under Weekly Scheduled Time'), //Is this needed? 'SB' => TTi18n::gettext( 'Not Scheduled Branch or Department' ), 'SC' => TTi18n::gettext( 'Not Scheduled Job or Task' ), 'ST' => TTi18n::gettext( 'Not Scheduled Punch Tags(s)' ), //Add setting to set some sort of "Grace" period, or early warning system? Approaching overtime? //Have exception where they can set the cutoff in hours, and it triggers once the employee has exceeded the weekly hours. 'O1' => TTi18n::gettext( 'Over Daily Time' ), 'O2' => TTi18n::gettext( 'Over Weekly Time' ), //Punch Exceptions 'M1' => TTi18n::gettext( 'Missing In Punch' ), 'M2' => TTi18n::gettext( 'Missing Out Punch' ), 'M3' => TTi18n::gettext( 'Missing Lunch In/Out Punch' ), 'M4' => TTi18n::gettext( 'Missing Break In/Out Punch' ), 'L1' => TTi18n::gettext( 'Long Lunch' ), 'L2' => TTi18n::gettext( 'Short Lunch' ), 'L3' => TTi18n::gettext( 'No Lunch' ), 'L4' => TTi18n::gettext( 'Late Lunch' ), //'L5' => TTi18n::gettext( 'Early Lunch' ), 'B1' => TTi18n::gettext( 'Long Break' ), 'B2' => TTi18n::gettext( 'Short Break' ), 'B3' => TTi18n::gettext( 'Too Many Breaks' ), 'B4' => TTi18n::gettext( 'Too Few Breaks' ), 'B5' => TTi18n::gettext( 'No Break' ), //Worked too long without break/lunch, allow to set the time frame. //Make grace period the amount of time a break has to exceed, and watch window the longest they can work without a break? //No Break exception essentially handles this. //'B6' => TTi18n::gettext('Worked Too Long without Break') //'B6' => TTi18n::gettext( 'Late Break' ), //For security guards typically, must check in (punch/transfer punch) every X hours or this alert goes out. 'C1' => TTi18n::gettext( 'Missed Check-In' ), //Branch/Department exceptions 'D1' => TTi18n::gettext( 'No Branch or Department' ), 'D2' => TTi18n::gettext( 'Not Allowed on Branch' ), 'D3' => TTi18n::gettext( 'Not Allowed on Department' ), //TimeSheet verification exceptions. 'V1' => TTi18n::gettext( 'TimeSheet Not Verified' ), //Job Exceptions 'J1' => TTi18n::gettext( 'Not Allowed On Job' ), 'J2' => TTi18n::gettext( 'Not Allowed On Task' ), 'J3' => TTi18n::gettext( 'Job Completed' ), 'J4' => TTi18n::gettext( 'No Job or Task' ), //'J5' => TTi18n::gettext('No Task'), //Make J4 No Job only? //Add location based exceptions, ie: Restricted Location. 'G1' => TTi18n::gettext( 'GEO Fence Violation' ), //Punch Tag Exceptions 'T1' => TTi18n::gettext( 'Not Allowed on Punch Tag(s)' ), 'T2' => TTi18n::gettext( 'No Punch Tag(s)' ), ]; break; case 'severity': $retval = [ 10 => TTi18n::gettext( 'Low' ), //Black 20 => TTi18n::gettext( 'Medium' ), //Blue 25 => TTi18n::gettext( 'High' ), //Orange 30 => TTi18n::gettext( 'Critical' ) //Rename to Critical: Red, was "High" ]; break; case 'email_notification': $retval = [ 0 => TTi18n::gettext( '-- None --' ), 10 => TTi18n::gettext( 'Employee' ), 20 => TTi18n::gettext( 'Supervisor' ), //20 => TTi18n::gettext('Immediate Supervisor'), //20 => TTi18n::gettext('All Supervisors'), 100 => TTi18n::gettext( 'Both' ), ]; break; case 'punch_notification': $retval = [ 0 => TTi18n::gettext( '-- None --' ), 10 => TTi18n::gettext( 'Warning' ), //12 => TTi18n::gettext( 'Warning (Contact)' ), //Message to contact supervisor 20 => TTi18n::gettext( 'Lock-Out' ), //Message to try again later or contact supervisor. //20 => TTi18n::gettext( 'Lock-Out (Retry)' ), //Message to simply retry later. //22 => TTi18n::gettext( 'Lock-Out (Contact)' ), //Message to contact supervisor ]; break; case 'columns': $retval = [ '-1010-active' => TTi18n::gettext( 'Active' ), '-1020-severity' => TTi18n::gettext( 'Severity' ), '-1030-grace' => TTi18n::gettext( 'Grace' ), '-1040-watch_window' => TTi18n::gettext( 'Watch Window' ), '-1050-email_notification' => TTi18n::gettext( 'Notify' ), '-1060-punch_notification' => TTi18n::gettext( 'Punch Notice' ), '-2000-created_by' => TTi18n::gettext( 'Created By' ), '-2010-created_date' => TTi18n::gettext( 'Created Date' ), '-2020-updated_by' => TTi18n::gettext( 'Updated By' ), '-2030-updated_date' => TTi18n::gettext( 'Updated Date' ), ]; break; } return $retval; } /** * @param $data * @return array */ function _getVariableToFunctionMap( $data ) { $variable_function_map = [ 'id' => 'ID', 'exception_policy_control_id' => 'ExceptionPolicyControl', 'name' => 'Name', 'type_id' => 'Type', 'severity_id' => 'Severity', 'is_enabled_watch_window' => 'isEnabledWatchWindow', 'watch_window' => 'WatchWindow', 'is_enabled_grace' => 'isEnabledGrace', 'grace' => 'Grace', 'is_enabled_punch_notice' => 'isEnabledPunchNotice', 'punch_notification_id' => 'PunchNotification', 'demerit' => 'Demerit', 'email_notification_id' => 'EmailNotification', 'active' => 'Active', 'deleted' => 'Deleted', ]; return $variable_function_map; } /** * @return bool */ function getExceptionPolicyControlObject() { return $this->getGenericObject( 'ExceptionPolicyControlListFactory', $this->getExceptionPolicyControl(), 'exception_policy_control_obj' ); } /** * @return bool|mixed */ function getExceptionPolicyControl() { return $this->getGenericDataValue( 'exception_policy_control_id' ); } /** * @param string $value UUID * @return bool */ function setExceptionPolicyControl( $value ) { $value = TTUUID::castUUID( $value ); return $this->setGenericDataValue( 'exception_policy_control_id', $value ); } /** * @param $exclude_exceptions * @param int $product_edition * @return array */ function getExceptionTypeDefaultValues( $exclude_exceptions, $product_edition = 10 ) { if ( !is_array( $exclude_exceptions ) ) { $exclude_exceptions = []; } $type_options = $this->getTypeOptions( $product_edition ); $retarr = []; foreach ( $type_options as $type_id => $exception_name ) { //Skip excluded exceptions if ( in_array( $type_id, $exclude_exceptions ) ) { continue; } switch ( $type_id ) { case 'S1': //UnSchedule Absence $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 25, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S2': //Not Scheduled $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 100, 'punch_notification_id' => 10, 'demerit' => 10, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S3': //In Early $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 10, 'email_notification_id' => 20, 'punch_notification_id' => 10, 'demerit' => 2, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 7200, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S4': //In Late $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 25, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 10, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 7200, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S5': //Out Early $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, //Don't default to warning, because depending on how they detect lunch/breaks it could cause problems. 'demerit' => 10, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 7200, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S6': //Out Late $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 10, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 7200, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S7': //Over daily scheduled time $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S8': //Under daily scheduled time $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'S9': //Over Weekly Scheduled Time $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'SB': //Not Scheduled Branch/Department $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'SC': //Not Scheduled Job/Task $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'ST': //Not Scheduled Punch Tag by $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'O1': //Over Daily Time $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => ( 3600 * 8 ), 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'O2': //Over Weekly Time $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => ( 3600 * 40 ), 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'M1': //Missing In Punch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 30, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 20, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'M2': //Missing Out Punch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 30, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 20, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'M3': //Missing Lunch In/Out Punch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 30, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 18, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'M4': //Missing Break In/Out Punch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 30, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 17, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'C1': //Missed Check-in $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 25, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 7200, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'D1': //No Job Or Task $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'D2': //Not allowed on branch. $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'D3': //Not allowed on department. $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'L1': //Long Lunch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'L2': //Short Lunch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 0, 'punch_notification_id' => 10, 'demerit' => 5, 'grace' => 900, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'L3': //No Lunch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 7, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'L4': //Late Lunch $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 7, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'B1': //Long Break $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 300, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'B2': //Short Break $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 0, 'punch_notification_id' => 10, 'demerit' => 5, 'grace' => 300, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'B3': //Too Many Breaks $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'B4': //Too Few Breaks $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'B5': //No Break $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 20, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'V1': //TimeSheet Not Verified $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 25, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => ( 48 * 3600 ), //48hrs grace period 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'J1': //Not allowed on job $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'J2': //Not allowed on task $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'J3': //Job completed $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'J4': //No Job Or Task $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'G1': //GEOFence $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 25, 'email_notification_id' => 100, 'punch_notification_id' => 0, 'demerit' => 15, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'T1': //Punch Tag Not Allowed $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => true, 'severity_id' => 20, 'email_notification_id' => 20, 'punch_notification_id' => 0, 'demerit' => 2, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; case 'T2': //No Punch Tag $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 5, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; default: $retarr[$type_id] = [ 'id' => -1, 'type_id' => $type_id, 'name' => $type_options[$type_id], 'active' => false, 'severity_id' => 10, 'email_notification_id' => 0, 'punch_notification_id' => 0, 'demerit' => 0, 'grace' => 0, 'is_enabled_grace' => $this->isEnabledGrace( $type_id ), 'watch_window' => 0, 'is_enabled_watch_window' => $this->isEnabledWatchWindow( $type_id ), 'is_enabled_punch_notice' => $this->isEnabledPunchNotice( $type_id ), ]; break; } } unset( $exception_name ); // code standards return $retarr; } /** * @return bool */ function getName() { return Option::getByKey( $this->getType(), $this->getTypeOptions( getTTProductEdition() ) ); } /** * @param int $product_edition * @return bool */ function getTypeOptions( $product_edition = 10 ) { $options = $this->getOptions( 'type' ); if ( getTTProductEdition() <= TT_PRODUCT_PROFESSIONAL || $product_edition <= TT_PRODUCT_PROFESSIONAL ) { $corporate_exceptions = [ 'J1', 'J2', 'J3', 'J4', 'SC', 'ST', 'C1', 'G1', 'T1', 'T2', 'D2', 'D3' ]; foreach ( $corporate_exceptions as $corporate_exception ) { unset( $options[$corporate_exception] ); } } return $options; } /** * @return bool|string */ function getType() { return (string)$this->getGenericDataValue( 'type_id' );//Should not be cast to int. } /** * @param $value * @return bool */ function setType( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'type_id', $value ); } /** * @return bool|int */ function getSeverity() { return $this->getGenericDataValue( 'severity_id' ); } /** * @param $value * @return bool */ function setSeverity( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'severity_id', $value ); } /** * @return bool|mixed */ function getWatchWindow() { return $this->getGenericDataValue( 'watch_window' ); } /** * @param $value * @return bool */ function setWatchWindow( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'watch_window', $value ); } /** * @return bool|mixed */ function getGrace() { return $this->getGenericDataValue( 'grace' ); } /** * @param $value * @return bool */ function setGrace( $value ) { $value = trim( $value ); return $this->setGenericDataValue( 'grace', $value ); } /** * @return bool|mixed */ function getDemerit() { return $this->getGenericDataValue( 'demerit' ); } /** * @param $value * @return bool */ function setDemerit( $value ) { return $this->setGenericDataValue( 'demerit', trim( $value ) ); } /** * @return bool|int */ function getPunchNotification() { return $this->getGenericDataValue( 'punch_notification_id' ); } /** * @param $value * @return bool */ function setPunchNotification( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'punch_notification_id', $value ); } /** * @return bool|int */ function getEmailNotification() { return $this->getGenericDataValue( 'email_notification_id' ); } /** * @param $value * @return bool */ function setEmailNotification( $value ) { $value = (int)trim( $value ); return $this->setGenericDataValue( 'email_notification_id', $value ); } /** * @return bool */ function getActive() { return $this->fromBool( $this->getGenericDataValue( 'active' ) ); } /** * @param $value * @return bool */ function setActive( $value ) { return $this->setGenericDataValue( 'active', $this->toBool( $value ) ); } /** * @param null $code * @return bool */ function isEnabledGrace( $code = null ) { if ( $code == null ) { $code = $this->getType(); } if ( in_array( $code, $this->enable_grace ) ) { return true; } return false; } /** * @param null $code * @return bool */ function isEnabledWatchWindow( $code = null ) { if ( $code == null ) { $code = $this->getType(); } if ( in_array( $code, $this->enable_watch_window ) ) { return true; } return false; } /** * @param null $code * @return bool */ function isEnabledPunchNotice( $code = null ) { if ( $code == null ) { $code = $this->getType(); } if ( in_array( $code, $this->enable_punch_notice ) ) { return true; } return false; } /** * @param $code * @return bool */ static function isPreMature( $code ) { if ( in_array( $code, self::$premature_exceptions ) ) { return true; } return false; } /** * This function needs to determine which new exceptions to create, and which old exceptions are no longer valid and to delete. * @param $existing_exceptions * @param $current_exceptions * @return array */ static function diffExistingAndCurrentExceptions( $existing_exceptions, $current_exceptions ) { //Debug::Arr($existing_exceptions, 'Existing Exceptions: ', __FILE__, __LINE__, __METHOD__, 10); //Debug::Arr($current_exceptions, 'Current Exceptions: ', __FILE__, __LINE__, __METHOD__, 10); if ( is_array( $existing_exceptions ) && count( $existing_exceptions ) == 0 ) { //No existing exceptions, nothing to delete or compare, just create new exceptions. return [ 'create_exceptions' => $current_exceptions, 'delete_exceptions' => [] ]; } $delete_exceptions = []; if ( is_array( $current_exceptions ) && count( $current_exceptions ) == 0 ) { //No current exceptions, delete all existing exceptions. foreach ( $existing_exceptions as $existing_exception ) { $delete_exceptions[] = $existing_exception['id']; } return [ 'create_exceptions' => [], 'delete_exceptions' => $delete_exceptions ]; } $new_exceptions = $current_exceptions; //Copy array so we can work from the copy. //Remove any current exceptions that already exist as existing exceptions. foreach ( $current_exceptions as $current_key => $current_exception ) { foreach ( $existing_exceptions as $existing_exception ) { //Need to match all elements except 'id'. if ( TTUUID::castUUID( $current_exception['exception_policy_id'] ) == TTUUID::castUUID( $existing_exception['exception_policy_id'] ) && (int)$current_exception['type_id'] == (int)$existing_exception['type_id'] && TTUUID::castUUID( $current_exception['user_id'] ) == TTUUID::castUUID( $existing_exception['user_id'] ) && (int)$current_exception['date_stamp'] == (int)$existing_exception['date_stamp'] && TTUUID::castUUID( $current_exception['punch_control_id'] ) == TTUUID::castUUID( $existing_exception['punch_control_id'] ) && TTUUID::castUUID( $current_exception['punch_id'] ) == TTUUID::castUUID( $existing_exception['punch_id'] ) ) { //Debug::text('Removing current exception that matches existing exception: '. $current_key, __FILE__, __LINE__, __METHOD__, 10); unset( $new_exceptions[$current_key] ); } //else { //Debug::text('NOT Removing current exception that matches existing exception: Current: '. $current_key .' Existing: '. $existing_key, __FILE__, __LINE__, __METHOD__, 10); } } //Mark any existing exceptions that are not in the current exception list for deletion. $delete_exceptions = []; $matched_key = []; $total_current_exceptions = count( $current_exceptions ); foreach ( $existing_exceptions as $existing_exception ) { $match_count = $total_current_exceptions; foreach ( $current_exceptions as $current_key => $current_exception ) { if ( !isset( $matched_key[$current_key] ) && ( $current_exception['exception_policy_id'] == $existing_exception['exception_policy_id'] && $current_exception['type_id'] == $existing_exception['type_id'] && $current_exception['user_id'] == $existing_exception['user_id'] && $current_exception['date_stamp'] == $existing_exception['date_stamp'] && $current_exception['punch_control_id'] == $existing_exception['punch_control_id'] && $current_exception['punch_id'] == $existing_exception['punch_id'] ) ) { //Make sure we don't match the same exception twice and allow duplicate exceptions to persist. //This fixes the issue where two S1 exceptions may have been created, but only one should really exist. $matched_key[$current_key] = true; } else { $match_count--; } /* if ( !( $current_exception['exception_policy_id'] == $existing_exception['exception_policy_id'] AND $current_exception['type_id'] == $existing_exception['type_id'] AND $current_exception['user_id'] == $existing_exception['user_id'] AND $current_exception['date_stamp'] == $existing_exception['date_stamp'] AND $current_exception['punch_control_id'] == $existing_exception['punch_control_id'] AND $current_exception['punch_id'] == $existing_exception['punch_id'] ) ) { Debug::text('a1Determining if we should delete this exception... Match Count: '. $match_count .' Total: '. $total_current_exceptions .' Existing Key: '. $existing_key, __FILE__, __LINE__, __METHOD__, 10); $match_count--; } */ //Debug::text('aDetermining if we should delete this exception... Match Count: '. $match_count .' Total: '. $total_current_exceptions .' Existing Key: '. $existing_key, __FILE__, __LINE__, __METHOD__, 10); } if ( $match_count == 0 ) { //Debug::text('bDetermining if we should delete this exception... Match Count: '. $match_count .' Total: '. $total_current_exceptions .' Existing Key: '. $existing_key, __FILE__, __LINE__, __METHOD__, 10); $delete_exceptions[] = $existing_exception['id']; } } $retarr = [ 'create_exceptions' => $new_exceptions, 'delete_exceptions' => $delete_exceptions ]; //Debug::Arr($retarr, 'RetArr Exceptions: ', __FILE__, __LINE__, __METHOD__, 10); return $retarr; } /** * @param string $exception_policy_control_id UUID * @param int $type_id * @param string $id UUID * @return bool */ function isUnique( $exception_policy_control_id, $type_id, $id ) { $ph = [ 'exception_policy_control_id' => $exception_policy_control_id, 'type_id' => trim( strtoupper( $type_id ) ), 'id' => TTUUID::castUUID( $id ), ]; $query = 'select id from ' . $this->getTable() . ' where exception_policy_control_id = ? AND type_id = ? AND id != ? AND deleted = 0'; $id = $this->db->GetOne( $query, $ph ); Debug::Arr( $id, 'Unique Exception Control ID: ' . $exception_policy_control_id . ' Type ID: ' . $type_id, __FILE__, __LINE__, __METHOD__, 10 ); if ( $id === false ) { return true; } else { if ( $id == $this->getId() ) { return true; } } return false; } /** * @param bool $ignore_warning * @return bool */ function Validate( $ignore_warning = true ) { // // BELOW: Validation code moved from set*() functions. // // Exception Policy Control $epclf = TTnew( 'ExceptionPolicyControlListFactory' ); /** @var ExceptionPolicyControlListFactory $epclf */ $this->Validator->isResultSetWithRows( 'exception_policy_control', $epclf->getByID( $this->getExceptionPolicyControl() ), TTi18n::gettext( 'Exception Policy Control is invalid' ) ); // Type $this->Validator->inArrayKey( 'type', $this->getType(), TTi18n::gettext( 'Incorrect Type' ), $this->getOptions( 'type' ) ); // Severity $this->Validator->inArrayKey( 'severity', $this->getSeverity(), TTi18n::gettext( 'Incorrect Severity' ), $this->getOptions( 'severity' ) ); // Watch Window if ( $this->getWatchWindow() != '' ) { $this->Validator->isNumeric( 'watch_window', $this->getWatchWindow(), TTi18n::gettext( 'Incorrect Watch Window' ) ); } // Grace value if ( $this->getGrace() != '' ) { $this->Validator->isNumeric( 'grace', $this->getGrace(), TTi18n::gettext( 'Incorrect grace value' ) ); } // Demerit value if ( $this->getDemerit() != '' ) { $this->Validator->isNumeric( 'demerit', $this->getDemerit(), TTi18n::gettext( 'Incorrect demerit value' ) ); $this->Validator->isGreaterThan( 'demerit', $this->getDemerit(), TTi18n::gettext( 'Demerit must be greater than -9999' ), -9999 ); $this->Validator->isLessThan( 'demerit', $this->getDemerit(), TTi18n::gettext( 'Demerit must be less than 9999' ), 9999 ); } // Email Notification $this->Validator->inArrayKey( 'email_notification', $this->getEmailNotification(), TTi18n::gettext( 'Incorrect Email Notification' ), $this->getOptions( 'email_notification' ) ); // Punch Notification $this->Validator->inArrayKey( 'punch_notification', $this->getPunchNotification(), TTi18n::gettext( 'Incorrect Punch Notification' ), $this->getOptions( 'punch_notification' ) ); // // ABOVE: Validation code moved from set*() functions. // if ( $this->isUnique( $this->getExceptionPolicyControl(), $this->getType(), $this->getID() ) == false ) { $this->Validator->isTrue( 'type_id', false, TTi18n::gettext( 'Duplicate exception already exists' ) ); } return true; } /** * @param $data * @return bool */ function setObjectFromArray( $data ) { if ( is_array( $data ) ) { $variable_function_map = $this->getVariableToFunctionMap(); foreach ( $variable_function_map as $key => $function ) { if ( isset( $data[$key] ) ) { $function = 'set' . $function; switch ( $key ) { case 'demerit': $this->$function( TTi18n::parseFloat( $data[$key] ) ); break; default: if ( method_exists( $this, $function ) ) { $this->$function( $data[$key] ); } break; } } } $this->setCreatedAndUpdatedColumns( $data ); return true; } return false; } /** * @param null $include_columns * @return array * @noinspection PhpMissingBreakStatementInspection */ function getObjectAsArray( $include_columns = null ) { $data = []; $variable_function_map = $this->getVariableToFunctionMap(); if ( is_array( $variable_function_map ) ) { foreach ( $variable_function_map as $variable => $function_stub ) { if ( $include_columns == null || ( isset( $include_columns[$variable] ) && $include_columns[$variable] == true ) ) { $function = 'get' . $function_stub; switch ( $variable ) { case 'demerit': $data[$variable] = Misc::removeTrailingZeros( $this->$function(), 2 ); break; //These must go immediately above the default case, as the missing break is intentional. case 'is_enabled_watch_window': case 'is_enabled_grace': case 'is_enabled_punch_notice': $function = str_replace( '_', '', $variable ); //Must not place a break here, as we just change the funtion name for the below default case. default: if ( method_exists( $this, $function ) ) { $data[$variable] = $this->$function(); } break; } } } $this->getCreatedAndUpdatedColumns( $data, $include_columns ); } return $data; } /** * This is called for every record everytime, and doesn't help much because of that. * This has to be enabled to properly log modifications though. * @param $log_action * @return bool */ function addLog( $log_action ) { return TTLog::addEntry( $this->getExceptionPolicyControl(), $log_action, TTi18n::getText( 'Exception Policy' ) . ' - ' . TTi18n::getText( 'Type' ) . ': ' . Option::getByKey( $this->getType(), $this->getOptions( 'type' ) ), null, $this->getTable(), $this ); } } ?>