function getShiftData($user_date_id = NULL, $user_id = NULL, $epoch = NULL, $filter = NULL, $tmp_punch_control_obj = NULL) { global $profiler; $profiler->startTimer('PayPeriodScheduleFactory::getShiftData()'); if (is_numeric($user_date_id) and $user_date_id > 0) { $user_id = $epoch = NULL; } if ($user_date_id == '' and $user_id == '' and $epoch == '') { return FALSE; } //Debug::text('User Date ID: '. $user_date_id .' User ID: '. $user_id .' TimeStamp: '. TTDate::getDate('DATE+TIME', $epoch), __FILE__, __LINE__, __METHOD__, 10); $new_shift_trigger_time = $this->getNewDayTriggerTime(); $plf = new PunchListFactory(); if ($user_date_id != '') { $plf->getByUserDateId($user_date_id); } else { //Get punches by time stamp. $punch_control_id = 0; if (is_object($tmp_punch_control_obj)) { $punch_control_id = $tmp_punch_control_obj->getId(); } $plf->getShiftPunchesByUserIDAndEpoch($user_id, $epoch, $punch_control_id, $this->getMaximumShiftTime()); unset($punch_control_id); } Debug::text('Punch Rows: ' . $plf->getRecordCount() . ' UserID: ' . $user_id . ' Date: ' . TTDate::getDate('DATE+TIME', $epoch) . '(' . $epoch . ') MaximumShiftTime: ' . $this->getMaximumShiftTime(), __FILE__, __LINE__, __METHOD__, 10); //Debug::Arr($punches, ' Punches: ', __FILE__, __LINE__, __METHOD__, 10); if ($plf->getRecordCount() > 0) { $shift = 0; $i = 0; $nearest_shift_id = 0; $nearest_punch_difference = FALSE; $prev_punch_obj = FALSE; foreach ($plf as $p_obj) { //Debug::text('Shift: '. $shift .' Punch ID: '. $p_obj->getID() .' Punch Control ID: '. $p_obj->getPunchControlID() .' TimeStamp: '. TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp() ), __FILE__, __LINE__, __METHOD__, 10); //If we're editing a punch, we need to use the object passed to this function instead of the one //from the database. if ($epoch == NULL) { //If user_date_id is passed without epoch, set epoch to the first punch we find. $epoch = $p_obj->getTimeStamp(); } if (isset($prev_punch_arr) and $p_obj->getTimeStamp() > $prev_punch_arr['time_stamp']) { $shift_data[$shift]['previous_punch_key'] = $i - 1; if ($shift_data[$shift]['previous_punch_key'] < 0) { $shift_data[$shift]['previous_punch_key'] = NULL; } } //Determine if a non-saved PunchControl object was passed, and if so, match the IDs to use that instead. if (is_object($tmp_punch_control_obj) and $p_obj->getPunchControlID() == $tmp_punch_control_obj->getId()) { Debug::text('Passed non-saved punch control object that matches, using that instead... Using ID: ' . (int) $tmp_punch_control_obj->getId(), __FILE__, __LINE__, __METHOD__, 10); $punch_control_obj = $tmp_punch_control_obj; } else { $punch_control_obj = $p_obj->getPunchControlObject(); } //Can't use PunchControl object total_time because the record may not be saved yet when editing //an already existing punch. //When editing, simply pass the existing PunchControl object to this function so we can //use it instead of the one in the database perhaps? $total_time = $punch_control_obj->getTotalTime(); /* //We can't skip records with total_time == 0, because then when deleting one of the two //punches in a pair, the remaining punch is ignored and causing punches to jump around between days in some cases. if ( $total_time == 0 ) { Debug::text('Total time is 0, skipping this punch control object...', __FILE__, __LINE__, __METHOD__, 10); //continue; } */ if ($i > 0 and isset($shift_data[$shift]['last_out']) and ($p_obj->getStatus() == 10 or $p_obj->getStatus() == $prev_punch_arr['status_id'])) { Debug::text('Checking for new shift...', __FILE__, __LINE__, __METHOD__, 10); if ($p_obj->getTimeStamp() - $shift_data[$shift]['last_out']['time_stamp'] > $new_shift_trigger_time) { $shift++; } } if (!isset($shift_data[$shift]['total_time'])) { $shift_data[$shift]['total_time'] = 0; } $punch_day_epoch = TTDate::getBeginDayEpoch($p_obj->getTimeStamp()); if (!isset($shift_data[$shift]['total_time_per_day'][$punch_day_epoch])) { $shift_data[$shift]['total_time_per_day'][$punch_day_epoch] = 0; } //Determine which shift is closest to the given epoch. $punch_difference_from_epoch = abs($epoch - $p_obj->getTimeStamp()); if ($nearest_punch_difference === FALSE or $punch_difference_from_epoch < $nearest_punch_difference) { Debug::text('Nearest Shift Determined to be: ' . $shift . ' Nearest Punch Diff: ' . (int) $nearest_punch_difference . ' Punch Diff: ' . $punch_difference_from_epoch, __FILE__, __LINE__, __METHOD__, 10); $nearest_shift_id = $shift; $nearest_punch_difference = $punch_difference_from_epoch; } $punch_arr = array('id' => $p_obj->getId(), 'punch_control_id' => $p_obj->getPunchControlId(), 'user_date_id' => $punch_control_obj->getUserDateID(), 'time_stamp' => $p_obj->getTimeStamp(), 'status_id' => $p_obj->getStatus(), 'type_id' => $p_obj->getType()); $shift_data[$shift]['punches'][] = $punch_arr; $shift_data[$shift]['punch_control_ids'][] = $p_obj->getPunchControlId(); if ($punch_control_obj->getUserDateID() != FALSE) { $shift_data[$shift]['user_date_ids'][] = $punch_control_obj->getUserDateID(); } $shift_data[$shift]['span_midnight'] = FALSE; if (!isset($shift_data[$shift]['first_in']) and $p_obj->getStatus() == 10) { //Debug::text('First In -- Punch ID: '. $p_obj->getID() .' Punch Control ID: '. $p_obj->getPunchControlID() .' TimeStamp: '. TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp() ), __FILE__, __LINE__, __METHOD__, 10); $shift_data[$shift]['first_in'] = $punch_arr; } elseif ($p_obj->getStatus() == 20) { //Debug::text('Last Out -- Punch ID: '. $p_obj->getID() .' Punch Control ID: '. $p_obj->getPunchControlID() .' TimeStamp: '. TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp() ), __FILE__, __LINE__, __METHOD__, 10); $shift_data[$shift]['last_out'] = $punch_arr; //Debug::text('Total Time: '. $total_time, __FILE__, __LINE__, __METHOD__, 10); $shift_data[$shift]['total_time'] += $total_time; //Check to see if the previous punch was on a different day then the current punch. if (isset($prev_punch_arr) and is_array($prev_punch_arr) and ($p_obj->getStatus() == 20 and $prev_punch_arr['status_id'] != 20) and TTDate::doesRangeSpanMidnight($prev_punch_arr['time_stamp'], $p_obj->getTimeStamp()) == TRUE) { Debug::text('Punch pair DOES span midnight', __FILE__, __LINE__, __METHOD__, 10); $shift_data[$shift]['span_midnight'] = TRUE; $total_time_for_each_day_arr = TTDate::calculateTimeOnEachDayBetweenRange($prev_punch_arr['time_stamp'], $p_obj->getTimeStamp()); if (is_array($total_time_for_each_day_arr)) { foreach ($total_time_for_each_day_arr as $begin_day_epoch => $day_total_time) { if (!isset($shift_data[$shift]['total_time_per_day'][$begin_day_epoch])) { $shift_data[$shift]['total_time_per_day'][$begin_day_epoch] = 0; } $shift_data[$shift]['total_time_per_day'][$begin_day_epoch] += $day_total_time; } } unset($total_time_for_each_day_arr, $begin_day_epoch, $day_total_time, $prev_day_total_time); } else { $shift_data[$shift]['total_time_per_day'][$punch_day_epoch] += $total_time; } } $prev_punch_arr = $punch_arr; $i++; } //Debug::Arr($shift_data, 'aShift Data:', __FILE__, __LINE__, __METHOD__, 10); if (isset($shift_data)) { //Loop through each shift to determine the day with the most time. foreach ($shift_data as $tmp_shift_key => $tmp_shift_data) { krsort($shift_data[$tmp_shift_key]['total_time_per_day']); //Sort by day first arsort($shift_data[$tmp_shift_key]['total_time_per_day']); //Sort by total time per day. reset($shift_data[$tmp_shift_key]['total_time_per_day']); $shift_data[$tmp_shift_key]['day_with_most_time'] = key($shift_data[$tmp_shift_key]['total_time_per_day']); $shift_data[$tmp_shift_key]['punch_control_ids'] = array_unique($shift_data[$tmp_shift_key]['punch_control_ids']); if (isset($shift_data[$tmp_shift_key]['user_date_ids'])) { $shift_data[$tmp_shift_key]['user_date_ids'] = array_unique($shift_data[$tmp_shift_key]['user_date_ids']); } } unset($tmp_shift_key, $tmp_shift_data); if ($filter == 'first_shift') { //Only return first shift. $shift_data = $shift_data[0]; } elseif ($filter == 'last_shift') { //Only return last shift. $shift_data = $shift_data[$shift]; } elseif ($filter == 'nearest_shift') { $shift_data = $shift_data[$nearest_shift_id]; //Check to make sure the nearest shift is within the new shift trigger time of EPOCH. if (isset($shift_data['first_in']['time_stamp'])) { $first_in = $shift_data['first_in']['time_stamp']; } elseif (isset($shift_data['last_out']['time_stamp'])) { $first_in = $shift_data['last_out']['time_stamp']; } if (isset($shift_data['last_out']['time_stamp'])) { $last_out = $shift_data['last_out']['time_stamp']; } elseif (isset($shift_data['first_in']['time_stamp'])) { $last_out = $shift_data['first_in']['time_stamp']; } if (TTDate::isTimeOverLap($epoch, $epoch, $first_in - $new_shift_trigger_time, $last_out + $new_shift_trigger_time) == FALSE) { Debug::Text('Nearest shift is outside the new shift trigger time... Epoch: ' . $epoch . ' First In: ' . $first_in . ' Last Out: ' . $last_out . ' New Shift Trigger: ' . $new_shift_trigger_time, __FILE__, __LINE__, __METHOD__, 10); return FALSE; } unset($first_in, $last_out); } $profiler->stopTimer('PayPeriodScheduleFactory::getShiftData()'); //Debug::Arr($shift_data, 'bShift Data:', __FILE__, __LINE__, __METHOD__, 10); return $shift_data; } } $profiler->stopTimer('PayPeriodScheduleFactory::getShiftData()'); return FALSE; }
function getInCompletePunchControlIdByUserIdAndEpoch($user_id, $epoch, $status_id) { Debug::text(' Epoch: ' . TTDate::getDate('DATE+TIME', $epoch), __FILE__, __LINE__, __METHOD__, 10); if ($user_id == '') { return FALSE; } if ($epoch == '') { return FALSE; } $plf = new PunchListFactory(); $plf->getShiftPunchesByUserIDAndEpoch($user_id, $epoch); if ($plf->getRecordCount() > 0) { //Check for gaps. $prev_time_stamp = 0; foreach ($plf as $p_obj) { if ($p_obj->getStatus() == 10) { $punch_arr[$p_obj->getPunchControlId()]['in'] = $p_obj->getTimeStamp(); } else { $punch_arr[$p_obj->getPunchControlId()]['out'] = $p_obj->getTimeStamp(); } if ($prev_time_stamp != 0) { $prev_punch_arr[$p_obj->getTimeStamp()] = $prev_time_stamp; } $prev_time_stamp = $p_obj->getTimeStamp(); } unset($prev_time_stamp); if (isset($prev_punch_arr)) { $next_punch_arr = array_flip($prev_punch_arr); } //Debug::Arr( $punch_arr, ' Punch Array: ', __FILE__, __LINE__, __METHOD__,10); //Debug::Arr( $next_punch_arr, ' Next Punch Array: ', __FILE__, __LINE__, __METHOD__,10); if (isset($punch_arr)) { $i = 0; foreach ($punch_arr as $punch_control_id => $data) { $found_gap = FALSE; Debug::text(' Iteration: ' . $i, __FILE__, __LINE__, __METHOD__, 10); //Skip complete punch control rows. if (isset($data['in']) and isset($data['out'])) { Debug::text(' Punch Control ID is Complete: ' . $punch_control_id, __FILE__, __LINE__, __METHOD__, 10); } else { //Make sure we don't assign a In punch that comes AFTER an Out punch to the same pair. //As well the opposite, an Out punch that comes BEFORE an In punch to the same pair. if ($status_id == 10 and !isset($data['in']) and (isset($data['out']) and $epoch <= $data['out'])) { Debug::text(' aFound Valid Gap...', __FILE__, __LINE__, __METHOD__, 10); $found_gap = TRUE; } elseif ($status_id == 20 and !isset($data['out']) and (isset($data['in']) and $epoch >= $data['in'])) { Debug::text(' bFound Valid Gap...', __FILE__, __LINE__, __METHOD__, 10); $found_gap = TRUE; } else { Debug::text(' No Valid Gap Found...', __FILE__, __LINE__, __METHOD__, 10); } } if ($found_gap == TRUE) { if ($status_id == 10) { //In Gap Debug::text(' In Gap...', __FILE__, __LINE__, __METHOD__, 10); if (isset($prev_punch_arr[$data['out']])) { Debug::text(' Punch Before In Gap... Range Start: ' . TTDate::getDate('DATE+TIME', $prev_punch_arr[$data['out']]) . ' End: ' . TTDate::getDate('DATE+TIME', $data['out']), __FILE__, __LINE__, __METHOD__, 10); if ($prev_punch_arr[$data['out']] == $data['out'] or TTDate::isTimeOverLap($epoch, $epoch, $prev_punch_arr[$data['out']], $data['out'])) { Debug::text(' Epoch OverLaps, THIS IS GOOD!', __FILE__, __LINE__, __METHOD__, 10); Debug::text(' aReturning Punch Control ID: ' . $punch_control_id, __FILE__, __LINE__, __METHOD__, 10); $retval = $punch_control_id; break; //Without this adding mass punches fails in some basic circumstances because it loops and attaches to a later punch control } else { Debug::text(' Epoch does not OverLaps, Cant attached to this punch_control!', __FILE__, __LINE__, __METHOD__, 10); } } else { //No Punch After Debug::text(' NO Punch Before In Gap...', __FILE__, __LINE__, __METHOD__, 10); $retval = $punch_control_id; break; } } else { //Out Gap Debug::text(' Out Gap...', __FILE__, __LINE__, __METHOD__, 10); //Start: $data['in'] //End: $data['in'] if (isset($next_punch_arr[$data['in']])) { Debug::text(' Punch After Out Gap... Range Start: ' . TTDate::getDate('DATE+TIME', $data['in']) . ' End: ' . TTDate::getDate('DATE+TIME', $next_punch_arr[$data['in']]), __FILE__, __LINE__, __METHOD__, 10); if ($data['in'] == $next_punch_arr[$data['in']] or TTDate::isTimeOverLap($epoch, $epoch, $data['in'], $next_punch_arr[$data['in']])) { Debug::text(' Epoch OverLaps, THIS IS GOOD!', __FILE__, __LINE__, __METHOD__, 10); Debug::text(' bReturning Punch Control ID: ' . $punch_control_id, __FILE__, __LINE__, __METHOD__, 10); $retval = $punch_control_id; break; //Without this adding mass punches fails in some basic circumstances because it loops and attaches to a later punch control } else { Debug::text(' Epoch does not OverLaps, Cant attached to this punch_control!', __FILE__, __LINE__, __METHOD__, 10); } } else { //No Punch After Debug::text(' NO Punch After Out Gap...', __FILE__, __LINE__, __METHOD__, 10); $retval = $punch_control_id; break; } } } $i++; } } } if (isset($retval)) { Debug::text(' Returning Punch Control ID: ' . $retval, __FILE__, __LINE__, __METHOD__, 10); return $retval; } Debug::text(' Returning FALSE No Valid Gaps Found...', __FILE__, __LINE__, __METHOD__, 10); //FALSE means no gaps in punch control rows found. return FALSE; }