示例#1
0
 function createExceptionPolicy($company_id)
 {
     $epcf = new ExceptionPolicyControlFactory();
     $epcf->setCompany($company_id);
     $epcf->setName('Default');
     if ($epcf->isValid()) {
         $epc_id = $epcf->Save();
         Debug::Text('aException Policy Control ID: ' . $epc_id, __FILE__, __LINE__, __METHOD__, 10);
         if ($epc_id === TRUE) {
             $epc_id = $data['id'];
         }
         Debug::Text('bException Policy Control ID: ' . $epc_id, __FILE__, __LINE__, __METHOD__, 10);
         $data['exceptions'] = array('S1' => array('active' => TRUE, 'severity_id' => 10), 'S2' => array('active' => TRUE, 'severity_id' => 30), 'S3' => array('active' => TRUE, 'severity_id' => 10, 'grace' => 300, 'watch_window' => 3600), 'S4' => array('active' => TRUE, 'severity_id' => 20, 'grace' => 300, 'watch_window' => 3600), 'S5' => array('active' => TRUE, 'severity_id' => 20, 'grace' => 300, 'watch_window' => 3600), 'S6' => array('active' => TRUE, 'severity_id' => 10, 'grace' => 300, 'watch_window' => 3600), 'S7' => array('active' => TRUE, 'severity_id' => 30), 'S8' => array('active' => TRUE, 'severity_id' => 10), 'M1' => array('active' => TRUE, 'severity_id' => 30), 'M2' => array('active' => TRUE, 'severity_id' => 30), 'L3' => array('active' => TRUE, 'severity_id' => 30), 'M3' => array('active' => TRUE, 'severity_id' => 30));
         if (count($data['exceptions']) > 0) {
             foreach ($data['exceptions'] as $code => $exception_data) {
                 Debug::Text('Looping Code: ' . $code, __FILE__, __LINE__, __METHOD__, 10);
                 $epf = new ExceptionPolicyFactory();
                 $epf->setExceptionPolicyControl($epc_id);
                 if (isset($exception_data['active'])) {
                     $epf->setActive(TRUE);
                 } else {
                     $epf->setActive(FALSE);
                 }
                 $epf->setType($code);
                 $epf->setSeverity($exception_data['severity_id']);
                 if (isset($exception_data['demerit']) and $exception_data['demerit'] != '') {
                     $epf->setDemerit($exception_data['demerit']);
                 }
                 if (isset($exception_data['grace']) and $exception_data['grace'] != '') {
                     $epf->setGrace($exception_data['grace']);
                 }
                 if (isset($exception_data['watch_window']) and $exception_data['watch_window'] != '') {
                     $epf->setWatchWindow($exception_data['watch_window']);
                 }
                 if ($epf->isValid()) {
                     $epf->Save();
                 }
             }
             Debug::Text('Creating Exception Policy ID: ' . $epc_id, __FILE__, __LINE__, __METHOD__, 10);
             return $epc_id;
         }
     }
     Debug::Text('Failed Creating Exception Policy!', __FILE__, __LINE__, __METHOD__, 10);
     return FALSE;
 }
 }
 $pplf = new PayPeriodListFactory();
 $pplf->getByCompanyId($current_company->getId());
 $pay_period_options = $pplf->getArrayByListFactory($pplf, FALSE, FALSE);
 $pay_period_ids = array_keys((array) $pay_period_options);
 if (isset($pay_period_ids[0]) and (!isset($filter_data['pay_period_id']) or $filter_data['pay_period_id'] == '')) {
     $filter_data['pay_period_id'] = '-1';
 }
 $filter_data['pay_period_status_id'] = array(10);
 $filter_data['type_id'] = array(30, 40, 50, 55, 60, 70);
 if (isset($filter_data['pre_mature'])) {
     $filter_data['type_id'][] = 5;
 }
 $elf->getSearchByCompanyIdAndArrayCriteria($current_company->getId(), $filter_data, $current_user_prefs->getItemsPerPage(), $page, NULL, $sort_array);
 $pager = new Pager($elf);
 $epf = new ExceptionPolicyFactory();
 $exception_policy_type_options = $epf->getOptions('type');
 $exception_policy_severity_options = $epf->getOptions('severity');
 $utlf = new UserTitleListFactory();
 $utlf->getByCompanyId($current_company->getId());
 $title_options = $utlf->getArrayByListFactory($utlf, FALSE, TRUE);
 $blf = new BranchListFactory();
 $blf->getByCompanyId($current_company->getId());
 $branch_options = $blf->getArrayByListFactory($blf, FALSE, TRUE);
 $dlf = new DepartmentListFactory();
 $dlf->getByCompanyId($current_company->getId());
 $department_options = $dlf->getArrayByListFactory($dlf, FALSE, TRUE);
 $uglf = new UserGroupListFactory();
 $group_options = $uglf->getArrayByNodes(FastTree::FormatArray($uglf->getByCompanyIdArray($current_company->getId()), 'TEXT', TRUE));
 $ulf = new UserListFactory();
 $user_options = $ulf->getByCompanyIdArray($current_company->getID(), FALSE);
/*
 * Get FORM variables
 */
extract(FormVariables::GetVariables(array('action', 'id', 'data')));
if (isset($data['exceptions'])) {
    foreach ($data['exceptions'] as $code => $exception) {
        if (isset($exception['grace']) and $exception['grace'] != '') {
            Debug::Text('Grace: ' . $exception['grace'], __FILE__, __LINE__, __METHOD__, 10);
            $data['exceptions'][$code]['grace'] = TTDate::parseTimeUnit($exception['grace']);
        }
        if (isset($exception['watch_window']) and $exception['watch_window'] != '') {
            $data['exceptions'][$code]['watch_window'] = TTDate::parseTimeUnit($exception['watch_window']);
        }
    }
}
$epf = new ExceptionPolicyFactory();
$epcf = new ExceptionPolicyControlFactory();
$action = Misc::findSubmitButton();
$action = strtolower($action);
switch ($action) {
    case 'submit':
        //Debug::setVerbosity(11);
        Debug::Text('Submit!', __FILE__, __LINE__, __METHOD__, 10);
        $epcf->setId($data['id']);
        $epcf->setCompany($current_company->getId());
        $epcf->setName($data['name']);
        if ($epcf->isValid()) {
            $epc_id = $epcf->Save();
            Debug::Text('aException Policy Control ID: ' . $epc_id, __FILE__, __LINE__, __METHOD__, 10);
            if ($epc_id === TRUE) {
                $epc_id = $data['id'];
 static function calcExceptions($user_date_id, $enable_premature_exceptions = FALSE, $enable_future_exceptions = TRUE)
 {
     global $profiler;
     $profiler->startTimer("ExceptionPolicy::calcExceptions()");
     if ($user_date_id == '') {
         return FALSE;
     }
     Debug::text(' User Date ID: ' . $user_date_id . ' PreMature: ' . (int) $enable_premature_exceptions, __FILE__, __LINE__, __METHOD__, 10);
     $current_epoch = TTDate::getTime();
     //Get user date info
     $udlf = TTnew('UserDateListFactory');
     $udlf->getById($user_date_id);
     if ($udlf->getRecordCount() > 0) {
         $user_date_obj = $udlf->getCurrent();
         if ($enable_future_exceptions == FALSE and $user_date_obj->getDateStamp() > TTDate::getEndDayEpoch($current_epoch)) {
             return FALSE;
         }
     } else {
         return FALSE;
     }
     //16hrs... If punches are older then this time, its no longer premature.
     //This should actually be the PayPeriod Schedule maximum shift time.
     if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
         self::$premature_delay = $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime();
         Debug::text(' Setting preMature Exception delay to maximum shift time: ' . self::$premature_delay, __FILE__, __LINE__, __METHOD__, 10);
     } else {
         self::$premature_delay = 57600;
     }
     //Get list of existing exceptions, so we can determine if we need to delete any. We can't delete them all blindly and re-create them
     //as this will send duplicate email notifications for every single punch.
     $existing_exceptions = array();
     $elf = TTnew('ExceptionListFactory');
     $elf->getByUserDateID($user_date_id);
     if ($elf->getRecordCount() > 0) {
         foreach ($elf as $e_obj) {
             $existing_exceptions[] = array('id' => $e_obj->getId(), 'user_date_id' => $e_obj->getUserDateID(), 'exception_policy_id' => $e_obj->getExceptionPolicyID(), 'type_id' => $e_obj->getType(), 'punch_id' => $e_obj->getPunchID(), 'punch_control_id' => $e_obj->getPunchControlID());
         }
     }
     unset($elf, $e_obj);
     //Get all Punches on this date for this user.
     $plf = TTnew('PunchListFactory');
     $plf->getByUserDateId($user_date_id);
     if ($plf->getRecordCount() > 0) {
         Debug::text(' Found Punches: ' . $plf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
     }
     $slf = TTnew('ScheduleListFactory');
     $slf->getByUserDateIdAndStatusId($user_date_id, 10);
     if ($slf->getRecordCount() > 0) {
         Debug::text(' Found Schedule: ' . $slf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
     }
     $schedule_id_cache = NULL;
     //Cache schedule IDs so we don't need to do a lookup for every exception.
     $current_exceptions = array();
     //Array holding current exception data.
     //Get all active exceptions.
     $eplf = TTnew('ExceptionPolicyListFactory');
     $eplf->getByPolicyGroupUserIdAndActive($user_date_obj->getUser(), TRUE);
     if ($eplf->getRecordCount() > 0) {
         Debug::text(' Found Active Exceptions: ' . $eplf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
         foreach ($eplf as $ep_obj) {
             //Debug::text(' Found Exception Type: '. $ep_obj->getType() .' ID: '. $ep_obj->getID() .' Control ID: '. $ep_obj->getExceptionPolicyControl(), __FILE__, __LINE__, __METHOD__,10);
             if ($enable_premature_exceptions == TRUE and self::isPreMature($ep_obj->getType()) == TRUE) {
                 //Debug::text(' Premature Exception: '. $ep_obj->getType() , __FILE__, __LINE__, __METHOD__,10);
                 $type_id = 5;
                 //Pre-Mature
             } else {
                 //Debug::text(' NOT Premature Exception: '. $ep_obj->getType() , __FILE__, __LINE__, __METHOD__,10);
                 $type_id = 50;
                 //Active
             }
             switch (strtolower($ep_obj->getType())) {
                 case 's1':
                     //Unscheduled Absence... Anytime they are scheduled and have not punched in.
                     //Ignore these exceptions if the schedule is after today (not including today),
                     //so if a supervisors schedules an employee two days in advance they don't get a unscheduled
                     //absence appearing right away.
                     //Since we now trigger In Late/Out Late exceptions immediately after schedule time, only trigger this exception after
                     //the schedule end time has passed.
                     //**We also need to handle shifts that start at 11:00PM on one day, end at 8:00AM the next day, and they are assigned to the day where
                     //the most time is worked (ie: the next day).
                     //Handle split shifts too...
                     //- This has a side affect that if the schedule policy start/stop time is set to 0, it will trigger both a UnScheduled Absence
                     //  and a Not Scheduled exception for the same schedule/punch.
                     //Loop through all schedules, then find punches to match.
                     if ($slf->getRecordCount() > 0) {
                         foreach ($slf as $s_obj) {
                             if ($s_obj->getStatus() == 10 and $current_epoch >= $s_obj->getEndTime()) {
                                 $add_exception = TRUE;
                                 //Debug::text(' Found Schedule: Start Time: '. TTDate::getDate('DATE+TIME', $s_obj->getStartTime() ), __FILE__, __LINE__, __METHOD__,10);
                                 //Find punches that fall within this schedule time including start/stop window.
                                 if (TTDate::doesRangeSpanMidnight($s_obj->getStartTime(), $s_obj->getEndTime()) and is_object($user_date_obj) and is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                                     //Get punches from both days.
                                     $plf_tmp = TTnew('PunchListFactory');
                                     $plf_tmp->getShiftPunchesByUserIDAndEpoch($user_date_obj->getUser(), $s_obj->getStartTime(), 0, $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime());
                                     Debug::text(' Schedule spans midnight... Found rows from expanded search: ' . $plf_tmp->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($plf_tmp->getRecordCount() > 0) {
                                         foreach ($plf_tmp as $p_obj_tmp) {
                                             if ($s_obj->inSchedule($p_obj_tmp->getTimeStamp())) {
                                                 Debug::text(' aFound punch for schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                 $add_exception = FALSE;
                                                 break;
                                             }
                                         }
                                     }
                                     unset($plf_tmp, $p_obj_tmp);
                                 } else {
                                     //Get punches from just this day.
                                     foreach ($plf as $p_obj) {
                                         if ($s_obj->inSchedule($p_obj->getTimeStamp())) {
                                             //Debug::text(' bFound punch for schedule...', __FILE__, __LINE__, __METHOD__,10);
                                             $add_exception = FALSE;
                                             break;
                                         }
                                     }
                                 }
                                 if ($add_exception == TRUE) {
                                     //Debug::text(' Adding S1 exception...', __FILE__, __LINE__, __METHOD__,10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'schedule_obj' => $s_obj);
                                 }
                             }
                         }
                     }
                     unset($s_obj, $add_exception);
                     break;
                 case 's2':
                     //Not Scheduled
                     //**We also need to handle shifts that start at 11:00PM on one day, end at 8:00AM the next day, and they are assigned to the day where
                     //the most time is worked (ie: the next day).
                     //Handle split shifts too...
                     if ($plf->getRecordCount() > 1) {
                         //Make sure at least two punche exist.
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 //Check if no schedule exists, or an absent schedule exists. If they work when not scheduled (no schedule) or schedule absent, both should trigger this.
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == FALSE or is_object($p_obj->getScheduleObject()) and $p_obj->getScheduleObject()->getStatus() == 20) {
                                     //Debug::text(' Worked when wasnt scheduled', __FILE__, __LINE__, __METHOD__,10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text('    Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     unset($scheduled_id_cache, $prev_punch_time_stamp, $p_obj);
                     break;
                 case 's3':
                     //In Early
                     if ($plf->getRecordCount() > 0) {
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() < $p_obj->getScheduleObject()->getStartTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     break;
                 case 's4':
                     //In Late
                     if ($plf->getRecordCount() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             Debug::text('    In Late. Punch: ' . TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp()), __FILE__, __LINE__, __METHOD__, 10);
                             //Ignore punches that have the exact same timestamp and/or punches with the transfer flag, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getTransfer() == FALSE and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() > $p_obj->getScheduleObject()->getStartTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     unset($scheduled_id_cache);
                     //Late Starting their shift, with no punch yet, trigger exception if:
                     //  - Schedule is found
                     //	- Current time is after schedule start time and before schedule end time.
                     // 	- Current time is after exception grace time
                     //Make sure we take into account split shifts.
                     Debug::text('    Checking Late Starting Shift exception... Current time: ' . TTDate::getDate('DATE+TIME', $current_epoch), __FILE__, __LINE__, __METHOD__, 10);
                     if ($slf->getRecordCount() > 0) {
                         foreach ($slf as $s_obj) {
                             if ($s_obj->getStatus() == 10 and ($current_epoch >= $s_obj->getStartTime() and $current_epoch <= $s_obj->getEndTime())) {
                                 if (TTDate::inWindow($current_epoch, $s_obj->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                     Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                 } else {
                                     //See if we can find a punch within the schedule time, if so assume we already created the exception above.
                                     //Make sure we take into account the schedule policy start/stop window.
                                     //However in the case where a single schedule shift and just one punch exists, if an employee comes in really
                                     //early (1AM) before the schedule start/stop window it will trigger an In Late exception.
                                     //This could still be correct though if they only come in for an hour, then come in late for their shift later.
                                     //Schedule start/stop time needs to be correct.
                                     //Also need to take into account shifts that span midnight, ie: 10:30PM to 6:00AM, as its important the schedules/punches match up properly.
                                     $add_exception = TRUE;
                                     Debug::text(' Found Schedule: Start Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getStartTime()), __FILE__, __LINE__, __METHOD__, 10);
                                     //Find punches that fall within this schedule time including start/stop window.
                                     if (TTDate::doesRangeSpanMidnight($s_obj->getStartTime(), $s_obj->getEndTime()) and is_object($user_date_obj) and is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                                         //Get punches from both days.
                                         $plf_tmp = TTnew('PunchListFactory');
                                         $plf_tmp->getShiftPunchesByUserIDAndEpoch($user_date_obj->getUser(), $s_obj->getStartTime(), 0, $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime());
                                         Debug::text(' Schedule spans midnight... Found rows from expanded search: ' . $plf_tmp->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
                                         if ($plf_tmp->getRecordCount() > 0) {
                                             foreach ($plf_tmp as $p_obj_tmp) {
                                                 if ($s_obj->inSchedule($p_obj_tmp->getTimeStamp())) {
                                                     Debug::text('    Found punch for this schedule, skipping schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                     $add_exception = FALSE;
                                                     continue 2;
                                                     //Skip to next schedule without creating exception.
                                                 }
                                             }
                                         }
                                         unset($plf_tmp, $p_obj_tmp);
                                     } else {
                                         //Get punches from just this day.
                                         foreach ($plf as $p_obj) {
                                             if ($s_obj->inSchedule($p_obj->getTimeStamp())) {
                                                 Debug::text(' bFound punch for schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                 $add_exception = FALSE;
                                                 break;
                                             }
                                         }
                                     }
                                     if ($add_exception == TRUE) {
                                         Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'schedule_obj' => $s_obj);
                                     }
                                 }
                             }
                         }
                     } else {
                         Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                     }
                     break;
                 case 's5':
                     //Out Early
                     if ($plf->getRecordCount() > 0) {
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         $total_punches = $plf->getRecordCount();
                         $x = 1;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp and/or punches with the transfer flag, as they are likely transfer punches.
                             //For Out Early, we have to wait until we are at the last punch, or there is a subsequent punch
                             // to see if it matches the exact same time (transfer)
                             //Therefore we need a two step confirmation before this exception can be triggered. Current punch, then next punch if it exists.
                             if ($p_obj->getTransfer() == FALSE and $p_obj->getType() == 10 and $p_obj->getStatus() == 20) {
                                 //Normal Out
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() < $p_obj->getScheduleObject()->getEndTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $tmp_exception = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                             if ($x == $total_punches) {
                                                 //Trigger exception if we're the last punch.
                                                 $current_exceptions[] = $tmp_exception;
                                             } else {
                                                 //Save exception to be triggered if the next punch doesn't match the same time.
                                             }
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             } elseif ($p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 //This comes after an OUT punch, so we need to check if there are two punches
                                 //in a row with the same timestamp, if so ignore the exception.
                                 if (isset($tmp_exception) and $p_obj->getTimeStamp() == $prev_punch_time_stamp) {
                                     unset($tmp_exception);
                                 } elseif (isset($tmp_exception)) {
                                     $current_exceptions[] = $tmp_exception;
                                     //Set exception.
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                             $x++;
                         }
                     }
                     unset($tmp_exception, $x, $prev_punch_time_stamp);
                     break;
                 case 's6':
                     //Out Late
                     if ($plf->getRecordCount() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'time_stamp' => $p_obj->getTimeStamp());
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 20) {
                                 //Normal Out
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() > $p_obj->getScheduleObject()->getEndTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                         //Trigger exception if no out punch and we have passed schedule out time.
                         //  - Schedule is found
                         //	- Make sure the user is missing an OUT punch.
                         //	- Current time is after schedule end time
                         // 	- Current time is after exception grace time
                         //  - Current time is before schedule end time + maximum shift time.
                         if (isset($punch_pairs) and $slf->getRecordCount() > 0) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 if (count($punch_pair) != 2) {
                                     Debug::text('aFound Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 10) {
                                         //Missing Out Punch
                                         Debug::text('bFound Missing Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         foreach ($slf as $s_obj) {
                                             Debug::text('Punch: ' . TTDate::getDate('DATE+TIME', $punch_pair[0]['time_stamp']) . ' Schedule Start Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getStartTime()) . ' End Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getEndTime()), __FILE__, __LINE__, __METHOD__, 10);
                                             //Because this is just an IN punch, make sure the IN punch is before the schedule end time
                                             //So we can eliminate split shift schedules.
                                             if ($punch_pair[0]['time_stamp'] <= $s_obj->getEndTime() and $current_epoch >= $s_obj->getEndTime() and $current_epoch <= $s_obj->getEndTime() + self::$premature_delay) {
                                                 if (TTDate::inWindow($current_epoch, $s_obj->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                                     Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                                 } else {
                                                     Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id'], 'schedule_obj' => $s_obj);
                                                 }
                                             }
                                         }
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm1':
                     //Missing In Punch
                     if ($plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             //Debug::text(' Punch: Status: '. $p_obj->getStatus() .' Punch Control ID: '. $p_obj->getPunchControlID() .' Punch ID: '. $p_obj->getId() .' TimeStamp: '. $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__,10);
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'punch_id' => $p_obj->getId());
                         }
                         if (isset($punch_pairs)) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 //Debug::Arr($punch_pair, 'Punch Pair for Control ID:'. $punch_control_id, __FILE__, __LINE__, __METHOD__,10);
                                 if (count($punch_pair) != 2) {
                                     Debug::text('a1Found Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 20) {
                                         //Missing In Punch
                                         Debug::text('b1Found Missing In Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id']);
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm2':
                     //Missing Out Punch
                     if ($plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' Punch ID: ' . $p_obj->getId() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                             //This causes the exception to trigger if the first punch pair is more than the Maximum Shift time away from the current punch,
                             //ie: In: 1:00AM, Out: 2:00AM, In 3:00PM (Maximum Shift Time less than 12hrs). The missing punch exception will be triggered immediately upon the 3:00PM punch.
                             //if ( $type_id == 5 AND $p_obj->getTimeStamp() < ($current_epoch-self::$premature_delay) ) {
                             //	$type_id = 50;
                             //}
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'time_stamp' => $p_obj->getTimeStamp());
                         }
                         if (isset($punch_pairs)) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 if (count($punch_pair) != 2) {
                                     Debug::text('a2Found Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 10) {
                                         //Missing Out Punch
                                         Debug::text('b2Found Missing Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         //Make sure we are at least MaximumShift Time from the matching In punch before trigging this exception.
                                         //Even when an supervisor is entering punches for today, make missing out punch pre-mature if the maximum shift time isn't exceeded.
                                         //This will prevent timesheet recalculations from having missing punches for everyone today.
                                         //if ( $type_id == 5 AND $punch_pair[0]['time_stamp'] < ($current_epoch-self::$premature_delay) ) {
                                         if ($punch_pair[0]['time_stamp'] < $current_epoch - self::$premature_delay) {
                                             $type_id = 50;
                                         } else {
                                             $type_id = 5;
                                         }
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id']);
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm3':
                     //Missing Lunch In/Out punch
                     if ($plf->getRecordCount() > 0) {
                         //We need to account for cases where they may punch IN from lunch first, then Out.
                         //As well as just a Lunch In punch and nothing else.
                         foreach ($plf as $p_obj) {
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punches[] = $p_obj;
                         }
                         if (isset($punches) and is_array($punches)) {
                             foreach ($punches as $key => $p_obj) {
                                 if ($p_obj->getType() == 20) {
                                     //Lunch
                                     Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($p_obj->getStatus() == 10) {
                                         //Make sure previous punch is Lunch/Out
                                         if (!isset($punches[$key - 1]) or isset($punches[$key - 1]) and is_object($punches[$key - 1]) and ($punches[$key - 1]->getType() != 20 or $punches[$key - 1]->getStatus() != 20)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     } else {
                                         //Make sure next punch is Lunch/In
                                         if (!isset($punches[$key + 1]) or isset($punches[$key + 1]) and is_object($punches[$key + 1]) and ($punches[$key + 1]->getType() != 20 or $punches[$key + 1]->getStatus() != 10)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     }
                                 }
                             }
                             unset($punches, $key, $p_obj);
                             if (isset($invalid_punches) and count($invalid_punches) > 0) {
                                 foreach ($invalid_punches as $invalid_punch_arr) {
                                     Debug::text('Found Missing Lunch In/Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $invalid_punch_arr['punch_id'], 'punch_control_id' => FALSE);
                                 }
                                 unset($invalid_punch_arr);
                             } else {
                                 Debug::text('Lunch Punches match up.', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($invalid_punches);
                         }
                     }
                     break;
                 case 'm4':
                     //Missing Break In/Out punch
                     if ($plf->getRecordCount() > 0) {
                         //We need to account for cases where they may punch IN from break first, then Out.
                         //As well as just a break In punch and nothing else.
                         foreach ($plf as $p_obj) {
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punches[] = $p_obj;
                         }
                         if (isset($punches) and is_array($punches)) {
                             foreach ($punches as $key => $p_obj) {
                                 if ($p_obj->getType() == 30) {
                                     //Break
                                     Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Type: ' . $p_obj->getType() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($p_obj->getStatus() == 10) {
                                         //Make sure previous punch is Break/Out
                                         if (!isset($punches[$key - 1]) or isset($punches[$key - 1]) and is_object($punches[$key - 1]) and ($punches[$key - 1]->getType() != 30 or $punches[$key - 1]->getStatus() != 20)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     } else {
                                         //Make sure next punch is Break/In
                                         if (!isset($punches[$key + 1]) or isset($punches[$key + 1]) and is_object($punches[$key + 1]) and ($punches[$key + 1]->getType() != 30 or $punches[$key + 1]->getStatus() != 10)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     }
                                 }
                             }
                             unset($punches, $key, $p_obj);
                             if (isset($invalid_punches) and count($invalid_punches) > 0) {
                                 foreach ($invalid_punches as $invalid_punch_arr) {
                                     Debug::text('Found Missing Break In/Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $invalid_punch_arr['punch_id'], 'punch_control_id' => FALSE);
                                 }
                                 unset($invalid_punch_arr);
                             } else {
                                 Debug::text('Lunch Punches match up.', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($invalid_punches);
                         }
                     }
                     break;
                 case 'c1':
                     //Missed Check-in
                     //Use grace period and make sure the employee punches within that period of time (usually a transfer punch, but break/lunch should work too)
                     if ($plf->getRecordCount() > 0 and $ep_obj->getGrace() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         $prev_punch_obj = FALSE;
                         $x = 1;
                         foreach ($plf as $p_obj) {
                             Debug::text('   Missed Check-In Punch: ' . TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp()) . ' Delay: ' . self::$premature_delay . ' Current Epoch: ' . $current_epoch, __FILE__, __LINE__, __METHOD__, 10);
                             //Handle punch pairs below. Only trigger on OUT punches.
                             if (is_object($prev_punch_obj) and $prev_punch_obj->getStatus() == 10 and $p_obj->getStatus() == 20 and $p_obj->getTimeStamp() - $prev_punch_time_stamp > $ep_obj->getGrace()) {
                                 //Only check OUT punches when paired.
                                 Debug::text('   Triggering excepetion as employee missed check-in within: ' . ($p_obj->getTimeStamp() - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                             } elseif ($prev_punch_time_stamp !== FALSE) {
                                 Debug::text('   Employee Checked-In within: ' . ($p_obj->getTimeStamp() - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                             }
                             //Handle cases where there is a IN punch but no OUT punch yet.
                             //However ignore cases where there is a OUT punch but no IN punch.
                             if ($x == $plf->getRecordCount() and $p_obj->getStatus() == 10 and $current_epoch - $p_obj->getTimeStamp() > $ep_obj->getGrace() and $p_obj->getTimeStamp() > $current_epoch - self::$premature_delay) {
                                 Debug::text('   Triggering excepetion as employee hasnt checked in yet, within: ' . ($current_epoch - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlID(), 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                             $prev_punch_obj = $p_obj;
                             $x++;
                         }
                     }
                     unset($prev_punch_obj, $prev_punch_time_stamp, $x);
                     break;
                 case 'd1':
                     //No Branch or Department
                     $add_exception = FALSE;
                     foreach ($plf as $p_obj) {
                         //In punches only
                         if ($p_obj->getStatus() == 10 and is_object($p_obj->getPunchControlObject())) {
                             //If no Tasks are setup, ignore checking them.
                             if ($p_obj->getPunchControlObject()->getBranch() == '' or $p_obj->getPunchControlObject()->getBranch() == 0 or $p_obj->getPunchControlObject()->getBranch() == FALSE) {
                                 $add_exception = TRUE;
                             }
                             if ($p_obj->getPunchControlObject()->getDepartment() == '' or $p_obj->getPunchControlObject()->getDepartment() == 0 or $p_obj->getPunchControlObject()->getDepartment() == FALSE) {
                                 //Make sure at least one task exists before triggering exception.
                                 $dlf = TTNew('DepartmentListFactory');
                                 $dlf->getByCompanyID($user_date_obj->getUserObject()->getCompany(), 1);
                                 //Limit to just 1 record.
                                 if ($dlf->getRecordCount() > 0) {
                                     $add_exception = TRUE;
                                 }
                             }
                             if ($add_exception === TRUE) {
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getId(), 'punch_control_id' => $p_obj->getPunchControlId());
                             }
                         }
                     }
                     break;
                 case 's7':
                     //Over Scheduled Hours
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         //FIXME: Do we want to trigger this before their last out punch?
                         $schedule_total_time = 0;
                         if ($slf->getRecordCount() > 0) {
                             //Check for schedule policy
                             foreach ($slf as $s_obj) {
                                 Debug::text(' Schedule Total Time: ' . $s_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10);
                                 $schedule_total_time += $s_obj->getTotalTime();
                             }
                             $daily_total_time = 0;
                             if ($schedule_total_time > 0) {
                                 //Get daily total time.
                                 $udtlf = TTnew('UserDateTotalListFactory');
                                 //Take into account auto-deduct/add meal policies, but not paid absences.
                                 //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                                 $udtlf->getByUserDateId($user_date_id);
                                 if ($udtlf->getRecordCount() > 0) {
                                     foreach ($udtlf as $udt_obj) {
                                         if ($udt_obj->getTimeCategory() == 'worked_time') {
                                             $daily_total_time += $udt_obj->getTotalTime();
                                         }
                                     }
                                 }
                                 Debug::text(' Daily Total Time: ' . $daily_total_time . ' Schedule Total Time: ' . $schedule_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                 if ($daily_total_time > 0 and $daily_total_time > $schedule_total_time + $ep_obj->getGrace()) {
                                     Debug::text(' Worked Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' Not Scheduled', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 's8':
                     //Under Scheduled Hours
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         $schedule_total_time = 0;
                         if ($slf->getRecordCount() > 0) {
                             //Check for schedule policy
                             foreach ($slf as $s_obj) {
                                 Debug::text(' Schedule Total Time: ' . $s_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10);
                                 $schedule_total_time += $s_obj->getTotalTime();
                             }
                             $daily_total_time = 0;
                             if ($schedule_total_time > 0) {
                                 //Get daily total time.
                                 $udtlf = TTnew('UserDateTotalListFactory');
                                 //Take into account auto-deduct/add meal policies
                                 //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                                 $udtlf->getByUserDateId($user_date_id);
                                 if ($udtlf->getRecordCount() > 0) {
                                     foreach ($udtlf as $udt_obj) {
                                         if ($udt_obj->getTimeCategory() == 'worked_time') {
                                             $daily_total_time += $udt_obj->getTotalTime();
                                         }
                                     }
                                 }
                                 Debug::text(' Daily Total Time: ' . $daily_total_time . ' Schedule Total Time: ' . $schedule_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                 if ($daily_total_time < $schedule_total_time - $ep_obj->getGrace()) {
                                     Debug::text(' Worked Under Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($type_id == 5 and $user_date_obj->getDateStamp() < TTDate::getBeginDayEpoch($current_epoch - self::$premature_delay)) {
                                         $type_id = 50;
                                     }
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text(' DID NOT Work Under Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' Not Scheduled', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'o1':
                     //Over Daily Time.
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         //FIXME: Do we want to trigger this before their last out punch?
                         $daily_total_time = 0;
                         //Get daily total time.
                         $udtlf = TTnew('UserDateTotalListFactory');
                         //Take into account auto-deduct/add meal policies
                         //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                         $udtlf->getByUserDateId($user_date_id);
                         if ($udtlf->getRecordCount() > 0) {
                             foreach ($udtlf as $udt_obj) {
                                 if ($udt_obj->getTimeCategory() == 'worked_time') {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                 }
                             }
                         }
                         Debug::text(' Daily Total Time: ' . $daily_total_time . ' Watch Window: ' . $ep_obj->getWatchWindow() . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         if ($daily_total_time > 0 and $daily_total_time > $ep_obj->getWatchWindow()) {
                             Debug::text(' Worked Over Daily Hours', __FILE__, __LINE__, __METHOD__, 10);
                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                         } else {
                             Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'o2':
                     //Over Weekly Time.
                 //Over Weekly Time.
                 case 's9':
                     //Over Weekly Scheduled Time.
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //Get Pay Period Schedule info
                         //FIXME: Do we want to trigger this before their last out punch?
                         if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                             $start_week_day_id = $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getStartWeekDay();
                         } else {
                             $start_week_day_id = 0;
                         }
                         Debug::text('Start Week Day ID: ' . $start_week_day_id, __FILE__, __LINE__, __METHOD__, 10);
                         $weekly_scheduled_total_time = 0;
                         //Currently we only consider committed scheduled shifts. We may need to change this to take into account
                         //recurring scheduled shifts that haven't been committed yet as well.
                         //In either case though we should take into account the entires week worth of scheduled time even if we are only partially through
                         //the week, that way we won't be triggering s9 exceptions on a Wed and a Fri or something, it will only occur on the last days of the week.
                         if (strtolower($ep_obj->getType()) == 's9') {
                             $tmp_slf = TTnew('ScheduleListFactory');
                             $tmp_slf->getByUserIdAndStartDateAndEndDate($user_date_obj->getUser(), TTDate::getBeginWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id), TTDate::getEndWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id));
                             if ($tmp_slf->getRecordCount() > 0) {
                                 foreach ($tmp_slf as $s_obj) {
                                     if ($s_obj->getStatus() == 10) {
                                         //Only working shifts.
                                         $weekly_scheduled_total_time += $s_obj->getTotalTime();
                                     }
                                 }
                             }
                             unset($tmp_slf, $s_obj);
                         }
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         $weekly_total_time = 0;
                         //Get daily total time.
                         $udtlf = TTnew('UserDateTotalListFactory');
                         $weekly_total_time = $udtlf->getWorkedTimeSumByUserIDAndStartDateAndEndDate($user_date_obj->getUser(), TTDate::getBeginWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id), $user_date_obj->getDateStamp());
                         Debug::text(' Weekly Total Time: ' . $weekly_total_time . ' Weekly Scheduled Total Time: ' . $weekly_scheduled_total_time . ' Watch Window: ' . $ep_obj->getWatchWindow() . ' Grace: ' . $ep_obj->getGrace() . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         //Don't trigger either of these exceptions unless both the worked and scheduled time is greater than 0. If they aren't scheduled at all
                         //it should trigger a Unscheduled Absence exception instead of a over weekly scheduled time exception.
                         if (strtolower($ep_obj->getType()) == 'o2' and $weekly_total_time > 0 and $weekly_total_time > $ep_obj->getWatchWindow() or strtolower($ep_obj->getType()) == 's9' and $weekly_scheduled_total_time > 0 and $weekly_total_time > 0 and $weekly_total_time > $weekly_scheduled_total_time + $ep_obj->getGrace()) {
                             Debug::text(' Worked Over Weekly Hours', __FILE__, __LINE__, __METHOD__, 10);
                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                         } else {
                             Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'l1':
                     //Long Lunch
                 //Long Lunch
                 case 'l2':
                     //Short Lunch
                     if ($plf->getRecordCount() > 0) {
                         //Get all lunch punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_lunch = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 20) {
                                 $lunch_out_timestamp = $p_obj->getTimeStamp();
                                 $lunch_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_lunch = TRUE;
                             } elseif ($out_for_lunch == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 20) {
                                 $lunch_punch_arr[$pair][20] = $lunch_out_timestamp;
                                 $lunch_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_lunch = FALSE;
                                 $pair++;
                                 unset($lunch_out_timestamp);
                             } else {
                                 $out_for_lunch = FALSE;
                             }
                         }
                         if (isset($lunch_punch_arr)) {
                             //Debug::Arr($lunch_punch_arr, 'Lunch Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($lunch_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $lunch_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Lunch Total Time: ' . $lunch_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $mp_obj = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getMealPolicyObject();
                                     } else {
                                         $mplf = TTnew('MealPolicyListFactory');
                                         $mplf->getByPolicyGroupUserId($user_date_obj->getUserObject()->getId());
                                         if ($mplf->getRecordCount() > 0) {
                                             Debug::text('Found Meal Policy to apply.', __FILE__, __LINE__, __METHOD__, 10);
                                             $mp_obj = $mplf->getCurrent();
                                         }
                                     }
                                     if (isset($mp_obj) and is_object($mp_obj)) {
                                         $meal_policy_lunch_time = $mp_obj->getAmount();
                                         Debug::text('Meal Policy Time: ' . $meal_policy_lunch_time, __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = FALSE;
                                         if (strtolower($ep_obj->getType()) == 'l1' and $meal_policy_lunch_time > 0 and $lunch_total_time > 0 and $lunch_total_time > $meal_policy_lunch_time + $ep_obj->getGrace()) {
                                             $add_exception = TRUE;
                                         } elseif (strtolower($ep_obj->getType()) == 'l2' and $meal_policy_lunch_time > 0 and $lunch_total_time > 0 and $lunch_total_time < $meal_policy_lunch_time - $ep_obj->getGrace()) {
                                             $add_exception = TRUE;
                                         }
                                         if ($add_exception == TRUE) {
                                             Debug::text('Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                             if (isset($time_stamp_arr['punch_id'])) {
                                                 $punch_id = $time_stamp_arr['punch_id'];
                                             } else {
                                                 $punch_id = FALSE;
                                             }
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                             unset($punch_id);
                                         } else {
                                             Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     }
                                 } else {
                                     Debug::text(' Lunch Punches not paired... Skipping!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' No Lunch Punches found, or none are paired.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'l3':
                     //No Lunch
                     if ($plf->getRecordCount() > 0) {
                         //If they are scheduled or not, we can check for a meal policy and base our
                         //decision off that. We don't want a No Lunch exception on a 3hr short shift though.
                         //Also ignore this exception if the lunch is auto-deduct.
                         //**Try to assign this exception to a specific punch control id, so we can do searches based on punch branch.
                         //Find meal policy
                         //Use scheduled meal policy first.
                         $meal_policy_obj = NULL;
                         if ($slf->getRecordCount() > 0) {
                             Debug::text('Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             foreach ($slf as $s_obj) {
                                 if ($s_obj->getSchedulePolicyObject() !== FALSE and $s_obj->getSchedulePolicyObject()->getMealPolicyObject() !== FALSE and $s_obj->getSchedulePolicyObject()->getMealPolicyObject()->getType() != 10) {
                                     Debug::text('Found Schedule Meal Policy... Trigger Time: ' . $s_obj->getSchedulePolicyObject()->getMealPolicyObject()->getTriggerTime(), __FILE__, __LINE__, __METHOD__, 10);
                                     $meal_policy_obj = $s_obj->getSchedulePolicyObject()->getMealPolicyObject();
                                 } else {
                                     Debug::text('Schedule Meal Policy does not exist, or is auto-deduct?', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text('No Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             //Check if they have a meal policy, with no schedule.
                             $mplf = TTnew('MealPolicyListFactory');
                             $mplf->getByPolicyGroupUserId($user_date_obj->getUser());
                             if ($mplf->getRecordCount() > 0) {
                                 foreach ($mplf as $mp_obj) {
                                     if ($mp_obj->getType() != 10) {
                                         Debug::text('Found UnScheduled meal Policy... Trigger Time: ' . $mp_obj->getTriggerTime(), __FILE__, __LINE__, __METHOD__, 10);
                                         $meal_policy_obj = $mp_obj;
                                     }
                                 }
                                 unset($mplf, $mp_obj);
                             } else {
                                 //There is no  meal policy or schedule policy with a meal policy assigned to it
                                 //With out this we could still apply No meal exceptions, but they will happen even on
                                 //a 2minute shift.
                                 Debug::text('No Lunch policy, applying No meal exception.', __FILE__, __LINE__, __METHOD__, 10);
                                 $meal_policy_obj = TRUE;
                             }
                         }
                         if (is_object($meal_policy_obj) or $meal_policy_obj === TRUE) {
                             $punch_control_id = FALSE;
                             $daily_total_time = 0;
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $udtlf->getByUserDateIdAndStatus($user_date_id, 20);
                             if ($udtlf->getRecordCount() > 0) {
                                 foreach ($udtlf as $udt_obj) {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                     $punch_control_total_time[$udt_obj->getPunchControlID()] = $udt_obj->getTotalTime();
                                 }
                             }
                             Debug::text('Day Total Time: ' . $daily_total_time, __FILE__, __LINE__, __METHOD__, 10);
                             //Debug::Arr($punch_control_total_time, 'Punch Control Total Time: ', __FILE__, __LINE__, __METHOD__,10);
                             if ($daily_total_time > 0 and ($meal_policy_obj === TRUE or $daily_total_time > $meal_policy_obj->getTriggerTime())) {
                                 //Check for meal punch.
                                 $meal_punch = FALSE;
                                 $tmp_punch_total_time = 0;
                                 $tmp_punch_control_ids = array();
                                 foreach ($plf as $p_obj) {
                                     if ($p_obj->getType() == 20) {
                                         //20 = Lunch
                                         Debug::text('Found meal Punch: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                         $meal_punch = TRUE;
                                         break;
                                     }
                                     if (isset($punch_control_total_time[$p_obj->getPunchControlID()]) and !isset($tmp_punch_control_ids[$p_obj->getPunchControlID()])) {
                                         $tmp_punch_total_time += $punch_control_total_time[$p_obj->getPunchControlID()];
                                         if ($punch_control_id === FALSE and ($meal_policy_obj === TRUE or $tmp_punch_total_time > $meal_policy_obj->getTriggerTime())) {
                                             Debug::text('Found punch control for exception: ' . $p_obj->getPunchControlID() . ' Total Time: ' . $tmp_punch_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                             $punch_control_id = $p_obj->getPunchControlID();
                                             //Don't meal the loop here, as we have to continue on and check for other meals.
                                         }
                                     }
                                     $tmp_punch_control_ids[$p_obj->getPunchControlID()] = TRUE;
                                 }
                                 unset($tmp_punch_total_time, $tmp_punch_control_ids);
                                 if ($meal_punch == FALSE) {
                                     Debug::text('Triggering No Lunch exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_control_id);
                                 }
                             }
                         }
                     }
                     break;
                 case 'b1':
                     //Long Break
                 //Long Break
                 case 'b2':
                     //Short Break
                     if ($plf->getRecordCount() > 0) {
                         //Get all break punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_break = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 30) {
                                 $break_out_timestamp = $p_obj->getTimeStamp();
                                 $break_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_break = TRUE;
                             } elseif ($out_for_break == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 30) {
                                 $break_punch_arr[$pair][20] = $break_out_timestamp;
                                 $break_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_break = FALSE;
                                 $pair++;
                                 unset($break_out_timestamp);
                             } else {
                                 $out_for_break = FALSE;
                             }
                         }
                         unset($pair);
                         if (isset($break_punch_arr)) {
                             //Debug::Arr($break_punch_arr, 'Break Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($break_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $break_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Break Total Time: ' . $break_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     $bplf = TTnew('BreakPolicyListFactory');
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $break_policy_ids = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getBreakPolicy();
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                     } else {
                                         $bplf->getByPolicyGroupUserId($user_date_obj->getUser());
                                     }
                                     unset($break_policy_ids);
                                     if ($bplf->getRecordCount() > 0) {
                                         Debug::text('Found Break Policy(ies) to apply: ' . $bplf->getRecordCount() . ' Pair: ' . $pair, __FILE__, __LINE__, __METHOD__, 10);
                                         foreach ($bplf as $bp_obj) {
                                             $bp_objs[] = $bp_obj;
                                         }
                                         unset($bplf, $bp_obj);
                                         if (isset($bp_objs[$pair]) and is_object($bp_objs[$pair])) {
                                             $bp_obj = $bp_objs[$pair];
                                             $break_policy_break_time = $bp_obj->getAmount();
                                             Debug::text('Break Policy Time: ' . $break_policy_break_time . ' ID: ' . $bp_obj->getID(), __FILE__, __LINE__, __METHOD__, 10);
                                             $add_exception = FALSE;
                                             if (strtolower($ep_obj->getType()) == 'b1' and $break_policy_break_time > 0 and $break_total_time > 0 and $break_total_time > $break_policy_break_time + $ep_obj->getGrace()) {
                                                 $add_exception = TRUE;
                                             } elseif (strtolower($ep_obj->getType()) == 'b2' and $break_policy_break_time > 0 and $break_total_time > 0 and $break_total_time < $break_policy_break_time - $ep_obj->getGrace()) {
                                                 $add_exception = TRUE;
                                             }
                                             if ($add_exception == TRUE) {
                                                 Debug::text('Adding Exception! ' . $ep_obj->getType(), __FILE__, __LINE__, __METHOD__, 10);
                                                 if (isset($time_stamp_arr['punch_id'])) {
                                                     $punch_id = $time_stamp_arr['punch_id'];
                                                 } else {
                                                     $punch_id = FALSE;
                                                 }
                                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                                 unset($punch_id);
                                             } else {
                                                 Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                             }
                                             unset($bp_obj);
                                         }
                                         unset($bp_objs);
                                     }
                                 } else {
                                     Debug::text(' Break Punches not paired... Skipping!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' No Break Punches found, or none are paired.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'b3':
                     //Too Many Breaks
                 //Too Many Breaks
                 case 'b4':
                     //Too Few Breaks
                     if ($plf->getRecordCount() > 0) {
                         //Get all break punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_break = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 30) {
                                 $break_out_timestamp = $p_obj->getTimeStamp();
                                 $break_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_break = TRUE;
                             } elseif ($out_for_break == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 30) {
                                 $break_punch_arr[$pair][20] = $break_out_timestamp;
                                 $break_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_break = FALSE;
                                 $pair++;
                                 unset($break_out_timestamp);
                             } else {
                                 $out_for_break = FALSE;
                             }
                         }
                         unset($pair);
                         //Get daily total time.
                         $daily_total_time = 0;
                         $udtlf = TTnew('UserDateTotalListFactory');
                         //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                         $udtlf->getByUserDateId($user_date_id);
                         if ($udtlf->getRecordCount() > 0) {
                             foreach ($udtlf as $udt_obj) {
                                 if ($udt_obj->getTimeCategory() == 'worked_time') {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                 }
                             }
                         }
                         Debug::text(' Daily Total Time: ' . $daily_total_time . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         //Make sure we take into account how long they have currently worked, so we don't
                         //say too few breaks for 3hr shift that they employee took one break on.
                         //Trigger this exception if the employee doesn't take a break at all?
                         if (isset($break_punch_arr)) {
                             $total_breaks = count($break_punch_arr);
                             //Debug::Arr($break_punch_arr, 'Break Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($break_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $break_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Break Total Time: ' . $break_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     $bplf = TTnew('BreakPolicyListFactory');
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $break_policy_ids = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getBreakPolicy();
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                     } else {
                                         //$bplf->getByPolicyGroupUserId( $user_date_obj->getUser() );
                                         $bplf->getByPolicyGroupUserIdAndDayTotalTime($user_date_obj->getUser(), $daily_total_time);
                                     }
                                     unset($break_policy_ids);
                                     $allowed_breaks = $bplf->getRecordCount();
                                     $add_exception = FALSE;
                                     if (strtolower($ep_obj->getType()) == 'b3' and $total_breaks > $allowed_breaks) {
                                         Debug::text(' Too many breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = TRUE;
                                     } elseif (strtolower($ep_obj->getType()) == 'b4' and $total_breaks < $allowed_breaks) {
                                         Debug::text(' Too few breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = TRUE;
                                     } else {
                                         Debug::text(' Proper number of breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                     if ($add_exception == TRUE and (strtolower($ep_obj->getType()) == 'b4' or strtolower($ep_obj->getType()) == 'b3' and $pair > $allowed_breaks - 1)) {
                                         Debug::text('Adding Exception! ' . $ep_obj->getType(), __FILE__, __LINE__, __METHOD__, 10);
                                         if (isset($time_stamp_arr['punch_id']) and strtolower($ep_obj->getType()) == 'b3') {
                                             $punch_id = $time_stamp_arr['punch_id'];
                                         } else {
                                             $punch_id = FALSE;
                                         }
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                         unset($punch_id);
                                     } else {
                                         Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 }
                             }
                         }
                     }
                     break;
                 case 'b5':
                     //No Break
                     if ($plf->getRecordCount() > 0) {
                         //If they are scheduled or not, we can check for a break policy and base our
                         //decision off that. We don't want a No Break exception on a 3hr short shift though.
                         //Also ignore this exception if the break is auto-deduct.
                         //**Try to assign this exception to a specific punch control id, so we can do searches based on punch branch.
                         //Find break policy
                         //Use scheduled break policy first.
                         $break_policy_obj = NULL;
                         if ($slf->getRecordCount() > 0) {
                             Debug::text('Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             foreach ($slf as $s_obj) {
                                 if ($s_obj->getSchedulePolicyObject() !== FALSE) {
                                     $break_policy_ids = $s_obj->getSchedulePolicyObject()->getBreakPolicy();
                                     if (is_array($break_policy_ids)) {
                                         $bplf = TTNew('BreakPolicyListFactory');
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                         if ($bplf->getRecordCount() > 0) {
                                             foreach ($bplf as $bp_obj) {
                                                 if ($bp_obj->getType() != 10) {
                                                     $break_policy_obj = $bp_obj;
                                                     break;
                                                 }
                                             }
                                         }
                                     }
                                 }
                                 unset($s_obj, $break_policy_ids, $bplf, $bp_obj);
                             }
                         } else {
                             Debug::text('No Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             //Check if they have a break policy, with no schedule.
                             $bplf = TTnew('BreakPolicyListFactory');
                             $bplf->getByPolicyGroupUserId($user_date_obj->getUser());
                             if ($bplf->getRecordCount() > 0) {
                                 Debug::text('Found UnScheduled Break Policy...', __FILE__, __LINE__, __METHOD__, 10);
                                 foreach ($bplf as $bp_obj) {
                                     if ($bp_obj->getType() != 10) {
                                         $break_policy_obj = $bp_obj;
                                         break;
                                     }
                                 }
                                 unset($bplf, $bp_obj);
                             } else {
                                 //There is no  break policy or schedule policy with a break policy assigned to it
                                 //With out this we could still apply No Break exceptions, but they will happen even on
                                 //a 2minute shift.
                                 Debug::text('No break policy, applying No break exception.', __FILE__, __LINE__, __METHOD__, 10);
                                 $break_policy_obj = TRUE;
                             }
                         }
                         if (is_object($break_policy_obj) or $break_policy_obj === TRUE) {
                             $punch_control_id = FALSE;
                             $daily_total_time = 0;
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $udtlf->getByUserDateIdAndStatus($user_date_id, 20);
                             if ($udtlf->getRecordCount() > 0) {
                                 foreach ($udtlf as $udt_obj) {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                     $punch_control_total_time[$udt_obj->getPunchControlID()] = $udt_obj->getTotalTime();
                                 }
                             }
                             Debug::text('Day Total Time: ' . $daily_total_time, __FILE__, __LINE__, __METHOD__, 10);
                             //Debug::Arr($punch_control_total_time, 'Punch Control Total Time: ', __FILE__, __LINE__, __METHOD__,10);
                             if ($daily_total_time > 0 and ($break_policy_obj === TRUE or $daily_total_time > $break_policy_obj->getTriggerTime())) {
                                 //Check for break punch.
                                 $break_punch = FALSE;
                                 $tmp_punch_total_time = 0;
                                 $tmp_punch_control_ids = array();
                                 foreach ($plf as $p_obj) {
                                     if ($p_obj->getType() == 30) {
                                         //30 = Break
                                         Debug::text('Found break Punch: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                         $break_punch = TRUE;
                                         break;
                                     }
                                     if (isset($punch_control_total_time[$p_obj->getPunchControlID()]) and !isset($tmp_punch_control_ids[$p_obj->getPunchControlID()])) {
                                         $tmp_punch_total_time += $punch_control_total_time[$p_obj->getPunchControlID()];
                                         if ($punch_control_id === FALSE and ($break_policy_obj === TRUE or $tmp_punch_total_time > $break_policy_obj->getTriggerTime())) {
                                             Debug::text('Found punch control for exception: ' . $p_obj->getPunchControlID(), __FILE__, __LINE__, __METHOD__, 10);
                                             $punch_control_id = $p_obj->getPunchControlID();
                                             //Don't break the loop here, as we have to continue on and check for other breaks.
                                         }
                                     }
                                     $tmp_punch_control_ids[$p_obj->getPunchControlID()] = TRUE;
                                 }
                                 unset($tmp_punch_total_time, $tmp_punch_control_ids);
                                 if ($break_punch == FALSE) {
                                     Debug::text('Triggering No Break exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_control_id);
                                 }
                             }
                         }
                     }
                     break;
                 case 'v1':
                     //TimeSheet Not Verified
                     //Get pay period schedule data, determine if timesheet verification is even enabled.
                     if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()) and $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getTimeSheetVerifyType() > 10) {
                         Debug::text('Verification enabled... Window Start: ' . TTDate::getDate('DATE+TIME', $user_date_obj->getPayPeriodObject()->getTimeSheetVerifyWindowStartDate()) . ' Grace Time: ' . $ep_obj->getGrace(), __FILE__, __LINE__, __METHOD__, 10);
                         //*Only* trigger this exception on the last day of the pay period, because when the pay period is verified it has to force the last day to be recalculated.
                         //Ignore timesheets without any time, (worked and absence). Or we could use the Watch Window to specify the minimum time required on
                         //a timesheet to trigger this instead?
                         //Make sure we are after the timesheet window start date + the grace period.
                         if ($user_date_obj->getPayPeriodObject()->getStatus() != 50 and $current_epoch >= $user_date_obj->getPayPeriodObject()->getTimeSheetVerifyWindowStartDate() + $ep_obj->getGrace() and TTDate::getBeginDayEpoch($user_date_obj->getDateStamp()) == TTDate::getBeginDayEpoch($user_date_obj->getPayPeriodObject()->getEndDate())) {
                             //Get pay period total time, include worked and paid absence time.
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $total_time = $udtlf->getTimeSumByUserIDAndPayPeriodId($user_date_obj->getUser(), $user_date_obj->getPayPeriodObject()->getID());
                             if ($total_time > 0) {
                                 //Check to see if pay period has been verified or not yet.
                                 $pptsvlf = TTnew('PayPeriodTimeSheetVerifyListFactory');
                                 $pptsvlf->getByPayPeriodIdAndUserId($user_date_obj->getPayPeriodObject()->getId(), $user_date_obj->getUser());
                                 $pay_period_verified = FALSE;
                                 if ($pptsvlf->getRecordCount() > 0) {
                                     $pay_period_verified = $pptsvlf->getCurrent()->getAuthorized();
                                 }
                                 if ($pay_period_verified == FALSE) {
                                     //Always allow for emailing this exception because it can be triggered after a punch is modified and
                                     //any supervisor would need to be notified to verify the timesheet again.
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'enable_email_notification' => TRUE);
                                 } else {
                                     Debug::text('TimeSheet has already been authorized!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             } else {
                                 Debug::text('Timesheet does not have any worked or paid absence time...', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($udtlf, $total_time);
                         } else {
                             Debug::text('Not within timesheet verification window, or not after grace time.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     } else {
                         Debug::text('No Pay Period Schedule or TimeSheet Verificiation disabled...', __FILE__, __LINE__, __METHOD__, 10);
                     }
                     break;
                 case 'j1':
                     //Not Allowed on Job
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         if ($j_obj->isAllowedUser($user_date_obj->getUser()) == FALSE) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    User allowed on Job!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     //Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__,10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j2':
                     //Not Allowed on Task
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0 and $p_obj->getPunchControlObject()->getJobItem() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         if ($j_obj->isAllowedItem($p_obj->getPunchControlObject()->getJobItem()) == FALSE) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    Job item allowed on job!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     //Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__,10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j3':
                     //Job already completed
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         //Status is completed and the User Date Stamp is greater then the job end date.
                                         //If no end date is set, ignore this.
                                         if ($j_obj->getStatus() == 30 and $j_obj->getEndDate() != FALSE and $user_date_obj->getDateStamp() > $j_obj->getEndDate()) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    Job Not Completed!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j4':
                     //No Job or Task
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             $add_exception = FALSE;
                             //In punches only
                             if ($p_obj->getStatus() == 10 and is_object($p_obj->getPunchControlObject())) {
                                 //If no Tasks are setup, ignore checking them.
                                 if ($p_obj->getPunchControlObject()->getJob() == '' or $p_obj->getPunchControlObject()->getJob() == 0 or $p_obj->getPunchControlObject()->getJob() == FALSE) {
                                     $add_exception = TRUE;
                                 }
                                 if ($p_obj->getPunchControlObject()->getJobItem() == '' or $p_obj->getPunchControlObject()->getJobItem() == 0 or $p_obj->getPunchControlObject()->getJobItem() == FALSE) {
                                     //Make sure at least one task exists before triggering exception.
                                     $jilf = TTNew('JobItemListFactory');
                                     $jilf->getByCompanyID($user_date_obj->getUserObject()->getCompany(), 1);
                                     //Limit to just 1 record.
                                     if ($jilf->getRecordCount() > 0) {
                                         $add_exception = TRUE;
                                     }
                                 }
                                 if ($add_exception === TRUE) {
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getId(), 'punch_control_id' => $p_obj->getPunchControlId());
                                 }
                             }
                         }
                     }
                     break;
                 default:
                     Debug::text('BAD, should never get here: ', __FILE__, __LINE__, __METHOD__, 10);
                     break;
             }
         }
     }
     unset($ep_obj);
     $exceptions = self::diffExistingAndCurrentExceptions($existing_exceptions, $current_exceptions);
     if (is_array($exceptions)) {
         if (isset($exceptions['create_exceptions']) and is_array($exceptions['create_exceptions']) and count($exceptions['create_exceptions']) > 0) {
             Debug::text('Creating new exceptions... Total: ' . count($exceptions['create_exceptions']), __FILE__, __LINE__, __METHOD__, 10);
             foreach ($exceptions['create_exceptions'] as $tmp_exception) {
                 $ef = TTnew('ExceptionFactory');
                 $ef->setUserDateID($tmp_exception['user_date_id']);
                 $ef->setExceptionPolicyID($tmp_exception['exception_policy_id']);
                 $ef->setType($tmp_exception['type_id']);
                 if (isset($tmp_exception['punch_control_id']) and $tmp_exception['punch_control_id'] != '') {
                     $ef->setPunchControlId($tmp_exception['punch_control_id']);
                 }
                 if (isset($tmp_exception['punch_id']) and $tmp_exception['punch_id'] != '') {
                     $ef->setPunchId($tmp_exception['punch_id']);
                 }
                 $ef->setEnableDemerits(TRUE);
                 if ($ef->isValid()) {
                     $ef->Save(FALSE);
                     //Save exception prior to emailing it, otherwise we can't save audit logs.
                     if ($enable_premature_exceptions == TRUE or isset($tmp_exception['enable_email_notification']) and $tmp_exception['enable_email_notification'] == TRUE) {
                         $eplf = TTnew('ExceptionPolicyListFactory');
                         $eplf->getById($tmp_exception['exception_policy_id']);
                         if ($eplf->getRecordCount() == 1) {
                             $ep_obj = $eplf->getCurrent();
                             $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, isset($tmp_exception['punch_obj']) ? $tmp_exception['punch_obj'] : NULL, isset($tmp_exception['schedule_obj']) ? $tmp_exception['schedule_obj'] : NULL, $ep_obj);
                         }
                     } else {
                         Debug::text('Not emailing new exception: User Date ID: ' . $tmp_exception['user_date_id'] . ' Type ID: ' . $tmp_exception['type_id'] . ' Enable PreMature: ' . (int) $enable_premature_exceptions, __FILE__, __LINE__, __METHOD__, 10);
                     }
                 }
                 unset($ef);
             }
         }
         if (isset($exceptions['delete_exceptions']) and is_array($exceptions['delete_exceptions']) and count($exceptions['delete_exceptions']) > 0) {
             Debug::Text('Deleting no longer valid exceptions... Total: ' . count($exceptions['delete_exceptions']), __FILE__, __LINE__, __METHOD__, 10);
             $ef = TTnew('ExceptionFactory');
             $ef->bulkDelete($exceptions['delete_exceptions']);
         }
     }
     $profiler->stopTimer("ExceptionPolicy::calcExceptions()");
     return TRUE;
 }
 static function reCalculateDay($user_date_id, $enable_exception = FALSE, $enable_premature_exceptions = FALSE, $enable_future_exceptions = TRUE, $enable_holidays = FALSE)
 {
     Debug::text('Re-calculating User Date ID: ' . $user_date_id . ' Enable Exception: ' . (int) $enable_exception, __FILE__, __LINE__, __METHOD__, 10);
     $udtf = TTnew('UserDateTotalFactory');
     //Make sure we wrap this in a transaction in case its called directly and an error occurs, the first thing that happens
     //is system entries are deleted, so we need to be able to recover from that.
     $udtf->StartTransaction();
     $udtf->setUserDateId($user_date_id);
     $udtf->calcSystemTotalTime();
     if ($enable_holidays == TRUE) {
         $holiday_user_date_ids = $udtf->getHolidayUserDateIDs();
         if (is_array($holiday_user_date_ids)) {
             foreach ($holiday_user_date_ids as $holiday_user_date_id) {
                 Debug::Text('reCalculating Holiday...', __FILE__, __LINE__, __METHOD__, 10);
                 if ($user_date_id != $holiday_user_date_id) {
                     //Don't recalculate the same day twice.
                     UserDateTotalFactory::reCalculateDay($holiday_user_date_id, FALSE, FALSE, FALSE, FALSE);
                 }
             }
         }
         unset($holiday_user_date_ids, $holiday_user_date_id);
     }
     if (!isset(self::$calc_exception) and $enable_exception == TRUE) {
         ExceptionPolicyFactory::calcExceptions($user_date_id, $enable_premature_exceptions, $enable_future_exceptions);
     }
     $udtf->CommitTransaction();
     return TRUE;
 }
    function getAPISearchByCompanyIdAndArrayCriteria($company_id, $filter_data, $limit = NULL, $page = NULL, $where = NULL, $order = NULL)
    {
        if ($company_id == '') {
            return FALSE;
        }
        if (!is_array($order)) {
            //Use Filter Data ordering if its set.
            if (isset($filter_data['sort_column']) and $filter_data['sort_order']) {
                $order = array(Misc::trimSortPrefix($filter_data['sort_column']) => $filter_data['sort_order']);
            }
        }
        if (isset($filter_data['user_group_id'])) {
            $filter_data['group_id'] = $filter_data['user_group_id'];
        }
        if (isset($filter_data['user_title_id'])) {
            $filter_data['title_id'] = $filter_data['user_title_id'];
        }
        if (isset($filter_data['include_user_id'])) {
            $filter_data['user_id'] = $filter_data['include_user_id'];
        }
        if (isset($filter_data['exception_policy_severity_id'])) {
            $filter_data['severity_id'] = $filter_data['exception_policy_severity_id'];
        }
        $additional_order_fields = array('d.name', 'e.name', 'f.name', 'g.name', 'h.status_id', 'i.severity_id', 'i.type_id', 'c.first_name', 'c.last_name', 'c.country', 'c.province', 'b.date_stamp', 'pgf.name', 'pscf.name', 'ppsf.name');
        $sort_column_aliases = array('status' => 'status_id', 'type' => 'type_id');
        $order = $this->getColumnsFromAliases($order, $sort_column_aliases);
        if ($order == NULL) {
            //$order = array( 'status_id' => 'asc', 'last_name' => 'asc', 'first_name' => 'asc', 'middle_name' => 'asc');
            $order = array('i.severity_id' => 'desc', 'c.last_name' => 'asc', 'b.date_stamp' => 'asc', 'i.type_id' => 'asc');
            $strict = FALSE;
        } else {
            //Do order by column conversions, because if we include these columns in the SQL
            //query, they contaminate the data array.
            if (isset($order['default_branch'])) {
                $order['d.name'] = $order['default_branch'];
                unset($order['default_branch']);
            }
            if (isset($order['default_department'])) {
                $order['e.name'] = $order['default_department'];
                unset($order['default_department']);
            }
            if (isset($order['user_group'])) {
                $order['f.name'] = $order['user_group'];
                unset($order['user_group']);
            }
            if (isset($order['title'])) {
                $order['g.name'] = $order['title'];
                unset($order['title']);
            }
            if (isset($order['exception_policy_type_id'])) {
                $order['i.type_id'] = $order['exception_policy_type_id'];
                unset($order['exception_policy_type_id']);
            }
            if (isset($order['severity_id'])) {
                $order['i.severity_id'] = $order['severity_id'];
                unset($order['severity_id']);
            }
            if (isset($order['severity'])) {
                $order['i.severity_id'] = $order['severity'];
                unset($order['severity']);
            }
            if (isset($order['exception_policy_type'])) {
                $order['i.type_id'] = $order['exception_policy_type'];
                unset($order['exception_policy_type']);
            }
            if (isset($order['exception_policy_type_id'])) {
                $order['i.type_id'] = $order['exception_policy_type_id'];
                unset($order['exception_policy_type_id']);
            }
            if (isset($order['first_name'])) {
                $order['c.first_name'] = $order['first_name'];
                unset($order['first_name']);
            }
            if (isset($order['last_name'])) {
                $order['c.last_name'] = $order['last_name'];
                unset($order['last_name']);
            }
            if (isset($order['country'])) {
                $order['c.country'] = $order['country'];
                unset($order['country']);
            }
            if (isset($order['province'])) {
                $order['c.province'] = $order['province'];
                unset($order['province']);
            }
            if (isset($order['date_stamp'])) {
                $order['b.date_stamp'] = $order['date_stamp'];
                unset($order['date_stamp']);
            }
            if (isset($order['policy_group'])) {
                $order['pgf.name'] = $order['policy_group'];
                unset($order['policy_group']);
            }
            if (isset($order['permission_group'])) {
                $order['pscf.name'] = $order['permission_group'];
                unset($order['permission_group']);
            }
            if (isset($order['pay_period_schedule'])) {
                $order['ppsf.name'] = $order['pay_period_schedule'];
                unset($order['pay_period_schedule']);
            }
            //Always sort by last name,first name after other columns
            if (!isset($order['c.last_name'])) {
                $order['c.last_name'] = 'asc';
            }
            if (!isset($order['c.first_name'])) {
                $order['c.first_name'] = 'asc';
            }
            if (!isset($order['b.date_stamp'])) {
                $order['b.date_stamp'] = 'asc';
            }
            if (!isset($order['i.severity_id'])) {
                $order['i.severity_id'] = 'desc';
            }
            $strict = TRUE;
        }
        //Debug::Arr($order,'Order Data:', __FILE__, __LINE__, __METHOD__,10);
        //Debug::Arr($filter_data,'Filter Data:', __FILE__, __LINE__, __METHOD__,10);
        $udf = new UserDateFactory();
        $uf = new UserFactory();
        $bf = new BranchFactory();
        $df = new DepartmentFactory();
        $ugf = new UserGroupFactory();
        $utf = new UserTitleFactory();
        $ppf = new PayPeriodFactory();
        $ppsf = new PayPeriodScheduleFactory();
        $epf = new ExceptionPolicyFactory();
        $epcf = new ExceptionPolicyControlFactory();
        $pguf = new PolicyGroupUserFactory();
        $pgf = new PolicyGroupFactory();
        $pf = new PunchFactory();
        $pcf = new PunchControlFactory();
        $pscf = new PermissionControlFactory();
        $puf = new PermissionUserFactory();
        $ph = array('company_id' => $company_id);
        $query = '
					select 	a.*,
							b.date_stamp as date_stamp,
							b.pay_period_id as pay_period_id,
							h.pay_period_schedule_id as pay_period_schedule_id,
							i.severity_id as severity_id,
							i.type_id as exception_policy_type_id,
							b.user_id as user_id,
                            h.start_date as pay_period_start_date,
							h.end_date as pay_period_end_date,
							h.transaction_date as pay_period_transaction_date,
							c.first_name as first_name,
							c.last_name as last_name,
                            c.country as country,
                            c.province as province,
							c.status_id as user_status_id,
							c.group_id as group_id,
							f.name as "group",
							c.title_id as title_id,
							g.name as title,
							c.default_branch_id as default_branch_id,
							d.name as default_branch,
							c.default_department_id as default_department_id,
							e.name as default_department,

							pcf.branch_id as branch_id,
							bf.name as branch,
							pcf.department_id as department_id,
							df.name as department,
                            pgf.name as policy_group,
                            pscf.name as permission_group,
                            ppsf.name as pay_period_schedule,

							y.first_name as created_by_first_name,
							y.middle_name as created_by_middle_name,
							y.last_name as created_by_last_name,
							z.first_name as updated_by_first_name,
							z.middle_name as updated_by_middle_name,
							z.last_name as updated_by_last_name
					from 	' . $this->getTable() . ' as a
						LEFT JOIN ' . $pf->getTable() . ' as pf ON ( a.punch_id IS NOT NULL AND a.punch_id = pf.id AND pf.deleted = 0)
						LEFT JOIN ' . $pcf->getTable() . ' as pcf ON ( ( ( pf.id IS NOT NULL AND pf.punch_control_id = pcf.id ) OR ( a.punch_control_id is NOT NULL AND a.punch_control_id = pcf.id ) ) AND pcf.deleted = 0)
						LEFT JOIN ' . $bf->getTable() . ' as bf ON pcf.branch_id = bf.id
						LEFT JOIN ' . $df->getTable() . ' as df ON pcf.department_id = df.id

						LEFT JOIN ' . $udf->getTable() . ' as b ON a.user_date_id = b.id
						LEFT JOIN ' . $uf->getTable() . ' as c ON b.user_id = c.id
						LEFT JOIN ' . $bf->getTable() . ' as d ON c.default_branch_id = d.id
						LEFT JOIN ' . $df->getTable() . ' as e ON c.default_department_id = e.id
						LEFT JOIN ' . $ugf->getTable() . ' as f ON c.group_id = f.id
						LEFT JOIN ' . $utf->getTable() . ' as g ON c.title_id = g.id
						LEFT JOIN ' . $ppf->getTable() . ' as h ON b.pay_period_id = h.id
                        LEFT JOIN ' . $ppsf->getTable() . ' as ppsf ON ppsf.id = h.pay_period_schedule_id
						LEFT JOIN ' . $epf->getTable() . ' as i ON a.exception_policy_id = i.id
                        LEFT JOIN ' . $epcf->getTable() . ' as epcf ON epcf.id = i.exception_policy_control_id
						LEFT JOIN ' . $pguf->getTable() . ' as pguf ON b.user_id = pguf.user_id
                        LEFT JOIN ' . $pgf->getTable() . ' as pgf ON pguf.policy_group_id = pgf.id
                        LEFT JOIN ' . $puf->getTable() . ' as puf ON c.id = puf.user_id
                        LEFT JOIN ' . $pscf->getTable() . ' as pscf ON pscf.id = puf.permission_control_id
						LEFT JOIN ' . $uf->getTable() . ' as y ON ( a.created_by = y.id AND y.deleted = 0 )
						LEFT JOIN ' . $uf->getTable() . ' as z ON ( a.updated_by = z.id AND z.deleted = 0 )
					where	c.company_id = ?
					';
        if (isset($filter_data['permission_children_ids']) and isset($filter_data['permission_children_ids'][0]) and !in_array(-1, (array) $filter_data['permission_children_ids'])) {
            $query .= ' AND c.id in (' . $this->getListSQL($filter_data['permission_children_ids'], $ph) . ') ';
        }
        if (isset($filter_data['id']) and isset($filter_data['id'][0]) and !in_array(-1, (array) $filter_data['id'])) {
            $query .= ' AND a.id in (' . $this->getListSQL($filter_data['id'], $ph) . ') ';
        }
        if (isset($filter_data['user_id']) and isset($filter_data['user_id'][0]) and !in_array(-1, (array) $filter_data['user_id'])) {
            $query .= ' AND c.id in (' . $this->getListSQL($filter_data['user_id'], $ph) . ') ';
        }
        $query .= isset($filter_data['exclude_user_id']) ? $this->getWhereClauseSQL('c.id', $filter_data['exclude_user_id'], 'not_numeric_list', $ph) : NULL;
        if (isset($filter_data['user_status_id']) and isset($filter_data['user_status_id'][0]) and !in_array(-1, (array) $filter_data['user_status_id'])) {
            $query .= ' AND c.status_id in (' . $this->getListSQL($filter_data['user_status_id'], $ph) . ') ';
        }
        if (isset($filter_data['type_id']) and isset($filter_data['type_id'][0]) and !in_array(-1, (array) $filter_data['type_id'])) {
            $query .= ' AND a.type_id in (' . $this->getListSQL($filter_data['type_id'], $ph) . ') ';
        }
        if (isset($filter_data['severity_id']) and isset($filter_data['severity_id'][0]) and !in_array(-1, (array) $filter_data['severity_id'])) {
            $query .= ' AND i.severity_id in (' . $this->getListSQL($filter_data['severity_id'], $ph) . ') ';
        }
        if (isset($filter_data['exception_policy_type_id']) and isset($filter_data['exception_policy_type_id'][0]) and !in_array(-1, (array) $filter_data['exception_policy_type_id'])) {
            $query .= ' AND i.type_id in (' . $this->getListSQL($filter_data['exception_policy_type_id'], $ph) . ') ';
        }
        if (isset($filter_data['pay_period_id']) and isset($filter_data['pay_period_id'][0]) and !in_array(-1, (array) $filter_data['pay_period_id'])) {
            $query .= ' AND b.pay_period_id in (' . $this->getListSQL($filter_data['pay_period_id'], $ph) . ') ';
        }
        if (isset($filter_data['pay_period_status_id']) and isset($filter_data['pay_period_status_id'][0]) and !in_array(-1, (array) $filter_data['pay_period_status_id'])) {
            $query .= ' AND h.status_id in (' . $this->getListSQL($filter_data['pay_period_status_id'], $ph) . ') ';
        }
        if (isset($filter_data['group_id']) and isset($filter_data['group_id'][0]) and !in_array(-1, (array) $filter_data['group_id'])) {
            if (isset($filter_data['include_subgroups']) and (bool) $filter_data['include_subgroups'] == TRUE) {
                $uglf = new UserGroupListFactory();
                $filter_data['group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray($company_id, $filter_data['group_id'], TRUE);
            }
            $query .= ' AND c.group_id in (' . $this->getListSQL($filter_data['group_id'], $ph) . ') ';
        }
        if (isset($filter_data['default_branch_id']) and isset($filter_data['default_branch_id'][0]) and !in_array(-1, (array) $filter_data['default_branch_id'])) {
            $query .= ' AND c.default_branch_id in (' . $this->getListSQL($filter_data['default_branch_id'], $ph) . ') ';
        }
        if (isset($filter_data['default_department_id']) and isset($filter_data['default_department_id'][0]) and !in_array(-1, (array) $filter_data['default_department_id'])) {
            $query .= ' AND c.default_department_id in (' . $this->getListSQL($filter_data['default_department_id'], $ph) . ') ';
        }
        if (isset($filter_data['title_id']) and isset($filter_data['title_id'][0]) and !in_array(-1, (array) $filter_data['title_id'])) {
            $query .= ' AND c.title_id in (' . $this->getListSQL($filter_data['title_id'], $ph) . ') ';
        }
        if (isset($filter_data['branch_id']) and isset($filter_data['branch_id'][0]) and !in_array(-1, (array) $filter_data['branch_id'])) {
            $query .= ' AND pcf.branch_id in (' . $this->getListSQL($filter_data['branch_id'], $ph) . ') ';
        }
        if (isset($filter_data['department_id']) and isset($filter_data['department_id'][0]) and !in_array(-1, (array) $filter_data['department_id'])) {
            $query .= ' AND pcf.department_id in (' . $this->getListSQL($filter_data['department_id'], $ph) . ') ';
        }
        if (isset($filter_data['start_date']) and trim($filter_data['start_date']) != '') {
            $ph[] = $this->db->BindDate($filter_data['start_date']);
            $query .= ' AND b.date_stamp >= ?';
        }
        if (isset($filter_data['end_date']) and trim($filter_data['end_date']) != '') {
            $ph[] = $this->db->BindDate($filter_data['end_date']);
            $query .= ' AND b.date_stamp <= ?';
        }
        $query .= isset($filter_data['created_by']) ? $this->getWhereClauseSQL(array('a.created_by', 'y.first_name', 'y.last_name'), $filter_data['created_by'], 'user_id_or_name', $ph) : NULL;
        $query .= isset($filter_data['updated_by']) ? $this->getWhereClauseSQL(array('a.updated_by', 'z.first_name', 'z.last_name'), $filter_data['updated_by'], 'user_id_or_name', $ph) : NULL;
        //Make sure we accept exception rows assign to pay_period_id = 0 (no pay period), as this can happen when punches exist in the future.
        $query .= '
						AND ( a.deleted = 0 AND b.deleted = 0 AND c.deleted = 0 AND pgf.deleted = 0 AND ( h.deleted = 0 OR h.deleted is NULL ) )
					';
        $query .= $this->getWhereSQL($where);
        $query .= $this->getSortSQL($order, $strict, $additional_order_fields);
        //Debug::Arr($ph, 'Query: '. $query, __FILE__, __LINE__, __METHOD__,10);
        $this->ExecuteSQL($query, $ph, $limit, $page);
        return $this;
    }
 function postSave()
 {
     //If status is pending auth (55=declined) delete all authorization history, because they could be re-verifying.
     if ($this->getCurrentUser() != FALSE and $this->getStatus() == 55) {
         $alf = TTnew('AuthorizationListFactory');
         $alf->getByObjectTypeAndObjectId(90, $this->getId());
         if ($alf->getRecordCount() > 0) {
             foreach ($alf as $a_obj) {
                 //Delete the record outright for now, as marking it as deleted causes transaction issues
                 //and it never gets committed.
                 $a_obj->Delete();
             }
         }
     }
     $time_sheet_verification_type_id = $this->getVerificationType();
     if ($time_sheet_verification_type_id > 10) {
         //10 = Disabled
         $authorize_timesheet = FALSE;
         if ($time_sheet_verification_type_id == 20) {
             //Employee Only
             $authorize_timesheet = TRUE;
         } elseif ($time_sheet_verification_type_id == 30) {
             //Superior Only
             if ($this->getStatus() == 30 and $this->getCurrentUser() != FALSE) {
                 //Check on CurrentUser so we don't loop indefinitely through AuthorizationFactory.
                 Debug::Text(' aAuthorizing TimeSheet as superior...', __FILE__, __LINE__, __METHOD__, 10);
                 $authorize_timesheet = TRUE;
             }
         } elseif ($time_sheet_verification_type_id == 40) {
             //Superior & Employee
             if ($this->getStatus() == 30 and $this->getCurrentUser() != FALSE and $this->getCurrentUser() != $this->getUser()) {
                 //Check on CurrentUser so we don't loop indefinitely through AuthorizationFactory.
                 Debug::Text(' bAuthorizing TimeSheet as superior...', __FILE__, __LINE__, __METHOD__, 10);
                 $authorize_timesheet = TRUE;
             }
         }
         if ($authorize_timesheet == TRUE) {
             $af = TTnew('AuthorizationFactory');
             $af->setCurrentUser($this->getCurrentUser());
             $af->setObjectType('timesheet');
             $af->setObject($this->getId());
             $af->setAuthorized(TRUE);
             if ($af->isValid()) {
                 $af->Save();
             }
         } else {
             Debug::Text('Not authorizing timesheet...', __FILE__, __LINE__, __METHOD__, 10);
         }
         if ($authorize_timesheet == TRUE or $this->getAuthorized() == TRUE) {
             //Recalculate exceptions on the last day of pay period to remove any TimeSheet Not Verified exceptions.
             //Get user_date_id.
             if (is_object($this->getPayPeriodObject())) {
                 $udlf = new UserDateListFactory();
                 $udlf->getByUserIdAndDate($this->getUser(), $this->getPayPeriodObject()->getEndDate());
                 if ($udlf->getRecordCount() > 0) {
                     Debug::Text('Recalculating exceptions on last day of pay period... Date: ' . $this->getPayPeriodObject()->getEndDate(), __FILE__, __LINE__, __METHOD__, 10);
                     ExceptionPolicyFactory::calcExceptions($udlf->getCurrent()->getID(), FALSE, FALSE);
                 }
             } else {
                 Debug::Text('No Pay Period found...', __FILE__, __LINE__, __METHOD__, 10);
             }
         } else {
             Debug::Text('Not recalculating last day of pay period...', __FILE__, __LINE__, __METHOD__, 10);
         }
     } else {
         Debug::Text('TimeSheet Verification is disabled...', __FILE__, __LINE__, __METHOD__, 10);
     }
     return TRUE;
 }
     }
     unset($exception_data_arr);
 }
 if (isset($date_exceptions)) {
     foreach ($calendar_array as $cal_arr) {
         if (isset($date_exceptions[$cal_arr['epoch']])) {
             $exception_data = $date_exceptions[$cal_arr['epoch']];
         } else {
             $exception_data = NULL;
         }
         $date_exception_total_rows[] = $exception_data;
     }
 }
 //Get exception names for legend.
 if (isset($unique_exceptions)) {
     $epf = new ExceptionPolicyFactory();
     $exception_options = $epf->getOptions('type');
     foreach ($unique_exceptions as $unique_exception) {
         $unique_exceptions[$unique_exception['exception_policy_type_id']]['name'] = $exception_options[$unique_exception['exception_policy_type_id']];
     }
     sort($unique_exceptions);
 }
 /*
 	Get Pending Requests
 */
 $rlf = new RequestListFactory();
 $rlf->getByCompanyIDAndUserIdAndStatusAndStartDateAndEndDate($current_company->getID(), $user_id, 30, $start_date, $end_date);
 if ($rlf->getRecordCount() > 0) {
     Debug::text('Found Requests!!: ', __FILE__, __LINE__, __METHOD__, 10);
     foreach ($rlf as $r_obj) {
         $user_date_stamp = TTDate::strtotime($r_obj->getColumn('date_stamp'));
    function getSearchByCompanyIdAndArrayCriteria($company_id, $filter_data, $limit = NULL, $page = NULL, $where = NULL, $order = NULL)
    {
        if ($company_id == '') {
            return FALSE;
        }
        if (!is_array($order)) {
            //Use Filter Data ordering if its set.
            if (isset($filter_data['sort_column']) and $filter_data['sort_order']) {
                $order = array(Misc::trimSortPrefix($filter_data['sort_column']) => $filter_data['sort_order']);
            }
        }
        $additional_order_fields = array('d.name', 'e.name', 'f.name', 'g.name', 'h.status_id', 'i.severity_id', 'i.type_id', 'c.first_name', 'c.last_name', 'b.date_stamp');
        if ($order == NULL) {
            //$order = array( 'status_id' => 'asc', 'last_name' => 'asc', 'first_name' => 'asc', 'middle_name' => 'asc');
            $order = array('i.severity_id' => 'desc', 'c.last_name' => 'asc', 'b.date_stamp' => 'asc', 'i.type_id' => 'asc');
            $strict = FALSE;
        } else {
            //Do order by column conversions, because if we include these columns in the SQL
            //query, they contaminate the data array.
            if (isset($order['default_branch'])) {
                $order['d.name'] = $order['default_branch'];
                unset($order['default_branch']);
            }
            if (isset($order['default_department'])) {
                $order['e.name'] = $order['default_department'];
                unset($order['default_department']);
            }
            if (isset($order['user_group'])) {
                $order['f.name'] = $order['user_group'];
                unset($order['user_group']);
            }
            if (isset($order['title'])) {
                $order['g.name'] = $order['title'];
                unset($order['title']);
            }
            if (isset($order['exception_policy_type_id'])) {
                $order['i.type_id'] = $order['exception_policy_type_id'];
                unset($order['exception_policy_type_id']);
            }
            if (isset($order['severity_id'])) {
                $order['i.severity_id'] = $order['severity_id'];
                unset($order['severity_id']);
            }
            if (isset($order['severity'])) {
                $order['i.severity_id'] = $order['severity'];
                unset($order['severity']);
            }
            if (isset($order['exception_policy_type'])) {
                $order['i.type_id'] = $order['exception_policy_type'];
                unset($order['exception_policy_type']);
            }
            if (isset($order['exception_policy_type_id'])) {
                $order['i.type_id'] = $order['exception_policy_type_id'];
                unset($order['exception_policy_type_id']);
            }
            if (isset($order['first_name'])) {
                $order['c.first_name'] = $order['first_name'];
                unset($order['first_name']);
            }
            if (isset($order['last_name'])) {
                $order['c.last_name'] = $order['last_name'];
                unset($order['last_name']);
            }
            if (isset($order['date_stamp'])) {
                $order['b.date_stamp'] = $order['date_stamp'];
                unset($order['date_stamp']);
            }
            //Always sort by last name,first name after other columns
            if (!isset($order['c.last_name'])) {
                $order['c.last_name'] = 'asc';
            }
            if (!isset($order['c.first_name'])) {
                $order['c.first_name'] = 'asc';
            }
            if (!isset($order['b.date_stamp'])) {
                $order['b.date_stamp'] = 'asc';
            }
            if (!isset($order['i.severity_id'])) {
                $order['i.severity_id'] = 'desc';
            }
            $strict = TRUE;
        }
        //Debug::Arr($order,'Order Data:', __FILE__, __LINE__, __METHOD__,10);
        //Debug::Arr($filter_data,'Filter Data:', __FILE__, __LINE__, __METHOD__,10);
        $udf = new UserDateFactory();
        $uf = new UserFactory();
        $bf = new BranchFactory();
        $df = new DepartmentFactory();
        $ugf = new UserGroupFactory();
        $utf = new UserTitleFactory();
        $ppf = new PayPeriodFactory();
        $epf = new ExceptionPolicyFactory();
        $ph = array('company_id' => $company_id);
        $query = '
					select 	a.*,
							b.date_stamp as user_date_stamp,
							i.severity_id as severity_id,
							i.type_id as exception_policy_type_id,
							b.user_id as user_id
					from 	' . $this->getTable() . ' as a
						LEFT JOIN ' . $udf->getTable() . ' as b ON a.user_date_id = b.id
						LEFT JOIN ' . $uf->getTable() . ' as c ON b.user_id = c.id
						LEFT JOIN ' . $bf->getTable() . ' as d ON c.default_branch_id = d.id
						LEFT JOIN ' . $df->getTable() . ' as e ON c.default_department_id = e.id
						LEFT JOIN ' . $ugf->getTable() . ' as f ON c.group_id = f.id
						LEFT JOIN ' . $utf->getTable() . ' as g ON c.title_id = g.id
						LEFT JOIN ' . $ppf->getTable() . ' as h ON b.pay_period_id = h.id
						LEFT JOIN ' . $epf->getTable() . ' as i ON a.exception_policy_id = i.id
					where	c.company_id = ?
					';
        if (isset($filter_data['permission_children_ids']) and isset($filter_data['permission_children_ids'][0]) and !in_array(-1, (array) $filter_data['permission_children_ids'])) {
            $query .= ' AND c.id in (' . $this->getListSQL($filter_data['permission_children_ids'], $ph) . ') ';
        }
        if (isset($filter_data['id']) and isset($filter_data['id'][0]) and !in_array(-1, (array) $filter_data['id'])) {
            $query .= ' AND c.id in (' . $this->getListSQL($filter_data['id'], $ph) . ') ';
        }
        if (isset($filter_data['user_id']) and isset($filter_data['user_id'][0]) and !in_array(-1, (array) $filter_data['user_id'])) {
            $query .= ' AND c.id in (' . $this->getListSQL($filter_data['user_id'], $ph) . ') ';
        }
        if (isset($filter_data['status_id']) and isset($filter_data['status_id'][0]) and !in_array(-1, (array) $filter_data['status_id'])) {
            $query .= ' AND c.status_id in (' . $this->getListSQL($filter_data['status_id'], $ph) . ') ';
        }
        if (isset($filter_data['type_id']) and isset($filter_data['type_id'][0]) and !in_array(-1, (array) $filter_data['type_id'])) {
            $query .= ' AND a.type_id in (' . $this->getListSQL($filter_data['type_id'], $ph) . ') ';
        }
        if (isset($filter_data['severity_id']) and isset($filter_data['severity_id'][0]) and !in_array(-1, (array) $filter_data['severity_id'])) {
            $query .= ' AND i.severity_id in (' . $this->getListSQL($filter_data['severity_id'], $ph) . ') ';
        }
        if (isset($filter_data['exception_policy_type_id']) and isset($filter_data['exception_policy_type_id'][0]) and !in_array(-1, (array) $filter_data['exception_policy_type_id'])) {
            $query .= ' AND i.type_id in (' . $this->getListSQL($filter_data['exception_policy_type_id'], $ph) . ') ';
        }
        if (isset($filter_data['pay_period_id']) and isset($filter_data['pay_period_id'][0]) and !in_array(-1, (array) $filter_data['pay_period_id'])) {
            $query .= ' AND b.pay_period_id in (' . $this->getListSQL($filter_data['pay_period_id'], $ph) . ') ';
        }
        if (isset($filter_data['pay_period_status_id']) and isset($filter_data['pay_period_status_id'][0]) and !in_array(-1, (array) $filter_data['pay_period_status_id'])) {
            $query .= ' AND h.status_id in (' . $this->getListSQL($filter_data['pay_period_status_id'], $ph) . ') ';
        }
        if (isset($filter_data['group_id']) and isset($filter_data['group_id'][0]) and !in_array(-1, (array) $filter_data['group_id'])) {
            if (isset($filter_data['include_subgroups']) and (bool) $filter_data['include_subgroups'] == TRUE) {
                $uglf = new UserGroupListFactory();
                $filter_data['group_id'] = $uglf->getByCompanyIdAndGroupIdAndSubGroupsArray($company_id, $filter_data['group_id'], TRUE);
            }
            $query .= ' AND c.group_id in (' . $this->getListSQL($filter_data['group_id'], $ph) . ') ';
        }
        if (isset($filter_data['default_branch_id']) and isset($filter_data['default_branch_id'][0]) and !in_array(-1, (array) $filter_data['default_branch_id'])) {
            $query .= ' AND c.default_branch_id in (' . $this->getListSQL($filter_data['default_branch_id'], $ph) . ') ';
        }
        if (isset($filter_data['default_department_id']) and isset($filter_data['default_department_id'][0]) and !in_array(-1, (array) $filter_data['default_department_id'])) {
            $query .= ' AND c.default_department_id in (' . $this->getListSQL($filter_data['default_department_id'], $ph) . ') ';
        }
        if (isset($filter_data['title_id']) and isset($filter_data['title_id'][0]) and !in_array(-1, (array) $filter_data['title_id'])) {
            $query .= ' AND c.title_id in (' . $this->getListSQL($filter_data['title_id'], $ph) . ') ';
        }
        /*
        if ( isset($filter_data['sin']) AND trim($filter_data['sin']) != '' ) {
        	$ph[] = trim($filter_data['sin']);
        	$query  .=	' AND a.sin LIKE ?';
        }
        */
        $query .= '
						AND ( a.deleted = 0 AND c.deleted = 0 AND h.deleted = 0 )
					';
        $query .= $this->getWhereSQL($where);
        $query .= $this->getSortSQL($order, $strict, $additional_order_fields);
        if ($limit == NULL) {
            $this->rs = $this->db->Execute($query, $ph);
        } else {
            $this->rs = $this->db->PageExecute($query, $limit, $page, $ph);
        }
        return $this;
    }
 static function reCalculateDay($user_date_id, $enable_exception = FALSE, $enable_premature_exceptions = FALSE, $enable_future_exceptions = TRUE, $enable_holidays = FALSE)
 {
     Debug::text('Re-calculating User Date ID: ' . $user_date_id . ' Enable Exception: ' . (int) $enable_exception, __FILE__, __LINE__, __METHOD__, 10);
     $udtf = new UserDateTotalFactory();
     $udtf->setUserDateId($user_date_id);
     $udtf->calcSystemTotalTime();
     if ($enable_holidays == TRUE) {
         $holiday_user_date_ids = $udtf->getHolidayUserDateIDs();
         //var_dump($holiday_user_date_ids);
         if (is_array($holiday_user_date_ids)) {
             foreach ($holiday_user_date_ids as $holiday_user_date_id) {
                 Debug::Text('reCalculating Holiday...', __FILE__, __LINE__, __METHOD__, 10);
                 UserDateTotalFactory::reCalculateDay($holiday_user_date_id, FALSE, FALSE, FALSE, FALSE);
             }
         }
         unset($holiday_user_date_ids, $holiday_user_date_id);
     }
     if (!isset(self::$calc_exception) and $enable_exception == TRUE) {
         ExceptionPolicyFactory::calcExceptions($user_date_id, $enable_premature_exceptions, $enable_future_exceptions);
     }
     return TRUE;
 }
    function getMidDayExceptionsByStartDateAndEndDateAndPayPeriodStatus($start_date, $end_date, $pay_period_status_id)
    {
        if ($start_date == '') {
            return FALSE;
        }
        if ($end_date == '') {
            return FALSE;
        }
        if ($pay_period_status_id == '') {
            return FALSE;
        }
        $epf = new ExceptionPolicyFactory();
        $ef = new ExceptionFactory();
        $epcf = new ExceptionPolicyControlFactory();
        $pgf = new PolicyGroupFactory();
        $pguf = new PolicyGroupUserFactory();
        $uf = new UserFactory();
        $cf = new CompanyFactory();
        $udf = new UserDateFactory();
        $sf = new ScheduleFactory();
        $pcf = new PunchControlFactory();
        $pf = new PunchFactory();
        $ppf = new PayPeriodFactory();
        $current_epoch = time();
        if (strncmp($this->db->databaseType, 'mysql', 5) == 0) {
            $to_timestamp_sql = 'FROM_UNIXTIME';
        } else {
            $to_timestamp_sql = 'to_timestamp';
        }
        $ph = array('current_time1' => $this->db->BindTimeStamp($current_epoch), 'current_time2' => $this->db->BindTimeStamp($current_epoch), 'current_epoch1' => $current_epoch, 'start_date' => $this->db->BindDate($start_date), 'end_date' => $this->db->BindDate($end_date));
        //Exceptions that need to be calculated in the middle of the day:
        //Definitely: In Late, Out Late, Missed CheckIn
        //Possible: Over Daily Scheduled Time, Over Weekly Scheduled Time, Over Daily Time, Over Weekly Time, Long Lunch (can't run this fast enough), Long Break (can't run this fast enough),
        //Optimize calcQuickExceptions:
        // Loop through exception policies where In Late/Out Late/Missed CheckIn are enabled.
        // Loop through ACTIVE users assigned to these exceptions policies.
        // Only find days that are scheduled AND ( NO punch after schedule start time OR NO punch after schedule end time )
        //      For Missed CheckIn they do not need to be scheduled.
        // Exclude days that already have the exceptions triggered on them (?) (What about split shifts?)
        //	- Just exclude exceptions not assigned to punch/punch_control_id, if there is more than one in the day I don't think it helps much anyways.
        //
        //Currently Over Weekly/Daily time exceptions are only triggered on a Out punch.
        $query = '	select distinct udf.*
					FROM ' . $epf->getTable() . ' as epf
					LEFT JOIN ' . $epcf->getTable() . ' as epcf ON ( epf.exception_policy_control_id = epcf.id )
					LEFT JOIN ' . $pgf->getTable() . ' as pgf ON ( epcf.id = pgf.exception_policy_control_id )
					LEFT JOIN ' . $pguf->getTable() . ' as pguf ON ( pgf.id = pguf.policy_group_id )
					LEFT JOIN ' . $uf->getTable() . ' as uf ON ( pguf.user_id = uf.id )
					LEFT JOIN ' . $cf->getTable() . ' as cf ON ( uf.company_id = cf.id )
					LEFT JOIN ' . $udf->getTable() . ' as udf ON ( uf.id = udf.user_id )
					LEFT JOIN ' . $ppf->getTable() . ' as ppf ON ( ppf.id = udf.pay_period_id )
					LEFT JOIN ' . $ef->getTable() . ' as ef ON ( udf.id = ef.user_date_id AND ef.exception_policy_id = epf.id AND ef.type_id != 5 )
					LEFT JOIN ' . $sf->getTable() . ' as sf ON ( udf.id = sf.user_date_id AND ( sf.start_time <= ? OR sf.end_time <= ? ) )
					LEFT JOIN ' . $pcf->getTable() . ' as pcf ON ( udf.id = pcf.user_date_id AND pcf.deleted = 0 )
					LEFT JOIN ' . $pf->getTable() . ' as pf ON 	(
																pcf.id = pf.punch_control_id AND pf.deleted = 0
																AND (
																		( epf.type_id = \'S4\' AND ( pf.time_stamp >= sf.start_time OR pf.time_stamp <= sf.end_time ) )
																		OR
																		( epf.type_id = \'S6\' AND ( pf.time_stamp >= sf.end_time ) )
																		OR
																		( epf.type_id = \'C1\' AND ( pf.status_id = 10 AND pf.time_stamp <= ' . $to_timestamp_sql . '(?-epf.grace) ) )
																	)
																)
					WHERE ( epf.type_id in (\'S4\',\'S6\', \'C1\') AND epf.active = 1 )
						AND ( uf.status_id = 10 AND cf.status_id != 30 )
						AND ( udf.date_stamp >= ? AND udf.date_stamp <= ? )
						AND ppf.status_id in (' . $this->getListSQL($pay_period_status_id, $ph) . ')
						AND ( ( ( epf.type_id in (\'S4\',\'S6\') AND ( sf.id IS NOT NULL AND sf.deleted = 0 ) AND pf.id IS NULL ) OR epf.type_id = \'C1\' ) AND ef.id IS NULL  )
						AND ( epf.deleted = 0 AND epcf.deleted = 0 AND pgf.deleted = 0 AND uf.deleted = 0 AND cf.deleted = 0 AND udf.deleted = 0 )
				';
        //Don't check deleted = 0 on PCF/PF tables, as we need to check IS NULL on them instead.
        //Debug::Arr($ph, 'Query: '. $query, __FILE__, __LINE__, __METHOD__, 10);
        $this->ExecuteSQL($query, $ph);
        return $this;
    }
示例#12
0
$execution_time = time();
//Calculate exceptions just for today and yesterday, because some shifts may start late in the day and need to be handled first thing in the morning.
//Make sure we also go one day in the future too, since the servers can be PST and if its 11:00PM, it will stop at midnight for that day, so
//shifts that would have already started in a different timezone (say EST) will not receive exceptions until we have moved into the next day for PST (3hrs late)
$start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($execution_time) - 86400);
$end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($execution_time) + 86400);
$udlf = new UserDateListFactory();
//Use optimized query to speed this process up significantly.
$udlf->getMidDayExceptionsByStartDateAndEndDateAndPayPeriodStatus($start_date, $end_date, array(10, 12, 15, 30));
Debug::text(' calcQuickExceptions: Start Date: ' . TTDate::getDate('DATE+TIME', $start_date) . ' End Date: ' . TTDate::getDate('DATE+TIME', $end_date) . ' User Date Rows: ' . $udlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 5);
if ($udlf->getRecordCount() > 0) {
    $i = 0;
    foreach ($udlf as $ud_obj) {
        $user_obj_prefs = $ud_obj->getUserObject()->getUserPreferenceObject();
        if (is_object($user_obj_prefs)) {
            $user_obj_prefs->setTimeZonePreferences();
        } else {
            //Use system timezone.
            TTDate::setTimeZone();
        }
        Debug::text('(' . $i . '). User: '******' Date: ' . TTDate::getDate('DATE+TIME', $ud_obj->getDateStamp()) . ' User Date ID: ' . $ud_obj->getId(), __FILE__, __LINE__, __METHOD__, 5);
        //Calculate pre-mature exceptions, so pre-mature Missing Out Punch exceptions arn't made active until they are ready.
        //Don't calculate future exceptions though.
        ExceptionPolicyFactory::calcExceptions($ud_obj->getId(), TRUE, FALSE);
        TTDate::setTimeZone();
        $i++;
    }
}
Debug::text(' calcQuickExceptions: Done', __FILE__, __LINE__, __METHOD__, 5);
Debug::writeToLog();
Debug::Display();