function testMaximumShiftTimeD() { global $dd; $this->createPayPeriodSchedule(10); $this->createPayPeriods(); $this->getAllPayPeriods(); $date_epoch = TTDate::getBeginWeekEpoch(time()); $date_stamp = TTDate::getDate('DATE', $date_epoch); $date_epoch2 = TTDate::getBeginDayEpoch(TTDate::getBeginWeekEpoch(time()) + 86400 + 3600); $date_stamp2 = TTDate::getDate('DATE', $date_epoch2); //Create two punch pairs with LESS than the minimum time between shifts, so they both fall on the same day, but are considered ONE shift and therefore fails. //However the last punch must be more than 16hrs away from the previous OUT punch (2:30PM) $dd->createPunchPair($this->user_id, strtotime($date_stamp . ' 1:00AM'), strtotime($date_stamp . ' 2:30PM'), array('in_type_id' => 10, 'out_type_id' => 10, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $dd->createPunchPair($this->user_id, strtotime($date_stamp . ' 6:15PM'), strtotime($date_stamp2 . ' 8:00AM'), array('in_type_id' => 10, 'out_type_id' => 10, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_arr = $this->getPunchDataArray(TTDate::getBeginDayEpoch($date_epoch), TTDate::getEndDayEpoch($date_epoch2)); //print_r($punch_arr); $this->assertEquals(2, count($punch_arr[$date_epoch][0]['shift_data']['punches'])); $this->assertEquals(1, count($punch_arr[$date_epoch][0]['shift_data']['punch_control_ids'])); //$this->assertEquals( $date_epoch, $punch_arr[$date_epoch][0]['date_stamp'] ); $udt_arr = $this->getUserDateTotalArray($date_epoch, $date_epoch2); //Total Time $this->assertEquals(10, $udt_arr[$date_epoch][0]['status_id']); $this->assertEquals(10, $udt_arr[$date_epoch][0]['type_id']); $this->assertEquals(13.5 * 3600, $udt_arr[$date_epoch][0]['total_time']); return TRUE; }
$pay_period_ids[] = $pay_period_obj->getId(); $pay_period_end_dates[$pay_period_obj->getId()] = $pay_period_obj->getEndDate(); if ($pp == 0) { $default_start_date = $pay_period_obj->getStartDate(); $default_end_date = $pay_period_obj->getEndDate(); } $pp++; } $pplf = TTnew('PayPeriodListFactory'); $pay_period_options = $pplf->getByIdListArray($pay_period_ids, NULL, array('start_date' => 'desc')); } if (isset($filter_data['start_date'])) { $filter_data['start_date'] = TTDate::getBeginDayEpoch(TTDate::parseDateTime($filter_data['start_date'])); } if (isset($filter_data['end_date'])) { $filter_data['end_date'] = TTDate::getEndDayEpoch(TTDate::parseDateTime($filter_data['end_date'])); } $filter_data = Misc::preSetArrayValues($filter_data, array('include_user_ids', 'exclude_user_ids', 'user_status_ids', 'group_ids', 'branch_ids', 'department_ids', 'schedule_branch_ids', 'schedule_department_ids', 'user_title_ids', 'pay_period_ids', 'include_job_ids', 'exclude_job_ids', 'job_branch_ids', 'job_department_ids', 'job_group_ids', 'client_ids', 'job_item_ids', 'job_item_group_ids', 'column_ids'), array()); //Get Permission Hierarchy Children first, as this can be used for viewing, or editing. $permission_children_ids = array(); $wage_permission_children_ids = array(); if ($permission->Check('user', 'view') == FALSE) { $hlf = TTnew('HierarchyListFactory'); $permission_children_ids = $wage_permission_children_ids = $hlf->getHierarchyChildrenByCompanyIdAndUserIdAndObjectTypeID($current_company->getId(), $current_user->getId()); Debug::Arr($permission_children_ids, 'Permission Children Ids:', __FILE__, __LINE__, __METHOD__, 10); if ($permission->Check('user', 'view_child') == FALSE) { $permission_children_ids = array(); } if ($permission->Check('user', 'view_own')) { $permission_children_ids[] = $current_user->getId(); }
function Validate() { Debug::Text('User Date ID: ' . $this->getUserDateID(), __FILE__, __LINE__, __METHOD__, 10); $this->handleDayBoundary(); $this->findUserDate(); Debug::text('User Date Id: ' . $this->getUserDateID(), __FILE__, __LINE__, __METHOD__, 10); //Check to make sure EnableOverwrite isn't enabled when editing an existing record. if ($this->isNew() == FALSE and $this->getEnableOverwrite() == TRUE) { Debug::Text('Overwrite enabled when editing existing record, disabling overwrite.', __FILE__, __LINE__, __METHOD__, 10); $this->setEnableOverwrite(FALSE); } if ($this->getUserDateObject() == FALSE or !is_object($this->getUserDateObject())) { Debug::Text('UserDateID is INVALID! ID: ' . $this->getUserDateID(), __FILE__, __LINE__, __METHOD__, 10); $this->Validator->isTrue('date_stamp', FALSE, TTi18n::gettext('Date/Time is incorrect, or pay period does not exist for this date. Please create a pay period schedule and assign this employee to it if you have not done so already')); } if (is_object($this->getUserDateObject()) and is_object($this->getUserDateObject()->getPayPeriodObject()) and $this->getUserDateObject()->getPayPeriodObject()->getIsLocked() == TRUE) { $this->Validator->isTrue('date_stamp', FALSE, TTi18n::gettext('Pay Period is Currently Locked')); } if ($this->getCompany() == FALSE) { $this->Validator->isTrue('company_id', FALSE, TTi18n::gettext('Company is invalid')); } if ($this->getDeleted() == FALSE and is_object($this->getUserDateObject()) and is_object($this->getUserDateObject()->getUserObject())) { if ($this->getUserDateObject()->getUserObject()->getHireDate() != '' and TTDate::getBeginDayEpoch($this->getUserDateObject()->getDateStamp()) < TTDate::getBeginDayEpoch($this->getUserDateObject()->getUserObject()->getHireDate())) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Shift is before employees hire date')); } if ($this->getUserDateObject()->getUserObject()->getTerminationDate() != '' and TTDate::getEndDayEpoch($this->getUserDateObject()->getDateStamp()) > TTDate::getEndDayEpoch($this->getUserDateObject()->getUserObject()->getTerminationDate())) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Shift is after employees termination date')); } } //Ignore conflicting time check when EnableOverwrite is set, as we will just be deleting any conflicting shift anyways. //Also ignore when setting OPEN shifts to allow for multiple. if ($this->getEnableOverwrite() == FALSE and $this->getDeleted() == FALSE and (is_object($this->getUserDateObject()) and $this->getUserDateObject()->getUser() > 0)) { $this->Validator->isTrue('start_time', !$this->isConflicting(), TTi18n::gettext('Conflicting start/end time, schedule already exists for this employee')); } else { Debug::text('Not checking for conflicts... UserDateObject: ' . (int) is_object($this->getUserDateObject()), __FILE__, __LINE__, __METHOD__, 10); } if ($this->isNew() == TRUE) { $obj_class = "TTLicense"; $obj_function = "validateLicense"; $obj_error_msg_function = "getFullErrorMessage"; @($obj = new $obj_class()); $retval = $obj->{$obj_function}(); if ($retval !== TRUE) { $this->Validator->isTrue('lic_obj', FALSE, $obj->{$obj_error_msg_function}($retval)); } } return TRUE; }
function _outputPDFForm($format = NULL) { $show_background = TRUE; if ($format == 'pdf_form_print' or $format == 'pdf_form_print_government' or $format == 'efile') { $show_background = FALSE; } Debug::Text('Generating Form... Format: ' . $format, __FILE__, __LINE__, __METHOD__, 10); $setup_data = $this->getFormConfig(); $filter_data = $this->getFilterConfig(); //Debug::Arr($filter_data, 'Filter Data: ', __FILE__, __LINE__, __METHOD__,10); $current_company = $this->getUserObject()->getCompanyObject(); if (!is_object($current_company)) { Debug::Text('Invalid company object...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } $current_user = $this->getUserObject(); if (!is_object($current_user)) { Debug::Text('Invalid user object...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } if ($format == 'efile_xml') { $return1040 = $this->getRETURN1040Object(); // Ceate the all needed data for Return1040.xsd at here. $return1040->return_created_timestamp = TTDate::getDBTimeStamp(TTDate::getTime(), FALSE); $return1040->year = TTDate::getYear($filter_data['end_date']); $return1040->tax_period_begin_date = TTDate::getDate('Y-m-d', TTDate::getBeginDayEpoch($filter_data['start_date'])); $return1040->tax_period_end__date = TTDate::getDate('Y-m-d', TTDate::getEndDayEpoch($filter_data['end_date'])); $return1040->software_id = ''; $return1040->originator_efin = ''; $return1040->originator_type_code = ''; $return1040->pin_type_code = ''; $return1040->jurat_disclosure_code = ''; $return1040->pin_entered_by = ''; $return1040->signature_date = TTDate::getDate('Y-m-d', TTDate::getTime()); $return1040->return_type = ''; $return1040->ssn = ''; $return1040->name = (isset($setup_data['company_name']) and $setup_data['company_name'] != '') ? $setup_data['company_name'] : $current_company->getName(); $return1040->name_control = ''; $return1040->address1 = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $return1040->city = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $return1040->state = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $return1040->zip_code = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); $return1040->ip_address = ''; $return1040->ip_date = TTDate::getDate('Y-m-d', TTDate::getTime()); $return1040->ip_time = TTDate::getDate('H:i:s', TTDate::getTime()); $return1040->timezone = TTDate::getTimeZone(); $this->getFormObject()->addForm($return1040); } $this->sortFormData(); //Make sure forms are sorted. $fw2 = $this->getFW2Object(); $fw2->setDebug(FALSE); //if ( $format == 'efile' ) { // $fw2->setDebug(TRUE); //} $fw2->setShowBackground($show_background); if (stristr($format, 'government')) { $form_type = 'government'; } else { $form_type = 'employee'; } Debug::Text('Form Type: ' . $form_type, __FILE__, __LINE__, __METHOD__, 10); $fw2->setType($form_type); $fw2->year = TTDate::getYear($filter_data['end_date']); //Add support for the user to manually set this data in the setup_data. That way they can use multiple tax IDs for different employees, all beit manually. $fw2->ein = (isset($setup_data['ein']) and $setup_data['ein'] != '') ? $setup_data['ein'] : $current_company->getBusinessNumber(); $fw2->name = (isset($setup_data['name']) and $setup_data['name'] != '') ? $setup_data['name'] : $this->getUserObject()->getFullName(); $fw2->trade_name = (isset($setup_data['company_name']) and $setup_data['company_name'] != '') ? $setup_data['company_name'] : $current_company->getName(); $fw2->company_address1 = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $fw2->company_city = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $fw2->company_state = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $fw2->company_zip_code = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); $fw2->efile_user_id = (isset($setup_data['efile_user_id']) and $setup_data['efile_user_id'] != '') ? $setup_data['efile_user_id'] : NULL; $fw2->efile_state = (isset($setup_data['efile_state']) and $setup_data['efile_state'] != '') ? $setup_data['efile_state'] : 0; $fw2->contact_name = $current_user->getFullName(); $fw2->contact_phone = $current_user->getWorkPhone(); $fw2->contact_phone_ext = $current_user->getWorkPhoneExt(); $fw2->contact_email = $current_user->getWorkEmail(); if (isset($this->form_data) and count($this->form_data) > 0) { $i = 0; $n = 1; foreach ((array) $this->form_data as $row) { if (!isset($row['user_id'])) { Debug::Text('User ID not set!', __FILE__, __LINE__, __METHOD__, 10); continue; } $ulf = TTnew('UserListFactory'); $ulf->getById((int) $row['user_id']); if ($ulf->getRecordCount() == 1) { $user_obj = $ulf->getCurrent(); $ee_data = array('control_number' => $n, 'first_name' => $user_obj->getFirstName(), 'middle_name' => $user_obj->getMiddleName(), 'last_name' => $user_obj->getLastName(), 'address1' => $user_obj->getAddress1(), 'address2' => $user_obj->getAddress2(), 'city' => $user_obj->getCity(), 'state' => $user_obj->getProvince(), 'employment_province' => $user_obj->getProvince(), 'zip_code' => $user_obj->getPostalCode(), 'ssn' => $user_obj->getSIN(), 'employee_number' => $user_obj->getEmployeeNumber(), 'l1' => $row['l1'], 'l2' => $row['l2'], 'l3' => $row['l3'], 'l4' => $row['l4'], 'l5' => $row['l5'], 'l6' => $row['l6'], 'l7' => $row['l7'], 'l8' => $row['l8'], 'l10' => $row['l10'], 'l11' => $row['l11'], 'l12a_code' => NULL, 'l12a' => NULL, 'l12b_code' => NULL, 'l12b' => NULL, 'l12c_code' => NULL, 'l12c' => NULL, 'l12d_code' => NULL, 'l12d' => NULL, 'l14a_name' => NULL, 'l14a' => NULL, 'l14b_name' => NULL, 'l14b' => NULL, 'l14c_name' => NULL, 'l14c' => NULL, 'l14d_name' => NULL, 'l14d' => NULL); if ($row['l12a'] > 0 and isset($setup_data['l12a_code']) and $setup_data['l12a_code'] != '') { $ee_data['l12a_code'] = $setup_data['l12a_code']; $ee_data['l12a'] = $row['l12a']; } if ($row['l12b'] > 0 and isset($setup_data['l12b_code']) and $setup_data['l12b_code'] != '') { $ee_data['l12b_code'] = $setup_data['l12b_code']; $ee_data['l12b'] = $row['l12b']; } if ($row['l12c'] > 0 and isset($setup_data['l12c_code']) and $setup_data['l12c_code'] != '') { $ee_data['l12c_code'] = $setup_data['l12c_code']; $ee_data['l12c'] = $row['l12c']; } if ($row['l12d'] > 0 and isset($setup_data['l12d_code']) and $setup_data['l12d_code'] != '') { $ee_data['l12d_code'] = $setup_data['l12d_code']; $ee_data['l12d'] = $row['l12d']; } if ($row['l14a'] > 0 and isset($setup_data['l14a_name']) and $setup_data['l14a_name'] != '') { $ee_data['l14a_name'] = $setup_data['l14a_name']; $ee_data['l14a'] = $row['l14a']; } if ($row['l14b'] > 0 and isset($setup_data['l14b_name']) and $setup_data['l14b_name'] != '') { $ee_data['l14b_name'] = $setup_data['l14b_name']; $ee_data['l14b'] = $row['l14b']; } if ($row['l14c'] > 0 and isset($setup_data['l14c_name']) and $setup_data['l14c_name'] != '') { $ee_data['l14c_name'] = $setup_data['l14c_name']; $ee_data['l14c'] = $row['l14c']; } if ($row['l14d'] > 0 and isset($setup_data['l14d_name']) and $setup_data['l14d_name'] != '') { $ee_data['l14d_name'] = $setup_data['l14d_name']; $ee_data['l14d'] = $row['l14d']; } foreach (range('a', 'z') as $z) { //State income tax if (isset($row['l16' . $z])) { if (isset($setup_data['state'][$row['l15' . $z . '_state']])) { $ee_data['l15' . $z . '_state_id'] = $setup_data['state'][$row['l15' . $z . '_state']]['state_id']; } $ee_data['l15' . $z . '_state'] = $row['l15' . $z . '_state']; $ee_data['l16' . $z] = $row['l16' . $z]; $ee_data['l17' . $z] = $row['l17' . $z]; } else { $ee_data['l15' . $z . '_state_id'] = NULL; $ee_data['l15' . $z . '_state'] = NULL; $ee_data['l16' . $z] = NULL; $ee_data['l17' . $z] = NULL; } //District income tax if (isset($row['l18' . $z])) { $ee_data['l18' . $z] = $row['l18' . $z]; $ee_data['l19' . $z] = $row['l19' . $z]; $ee_data['l20' . $z] = $row['l20' . $z]; } else { $ee_data['l18' . $z] = NULL; $ee_data['l19' . $z] = NULL; $ee_data['l20' . $z] = NULL; } } $fw2->addRecord($ee_data); unset($ee_data); $i++; $n++; } } } $this->getFormObject()->addForm($fw2); if ($form_type == 'government') { //Handle W3 $fw3 = $this->getFW3Object(); $fw3->setShowBackground($show_background); $fw3->year = $fw2->year; $fw3->ein = $fw2->ein; $fw3->name = $fw2->name; $fw3->trade_name = $fw2->trade_name; $fw3->company_address1 = $fw2->company_address1; $fw3->company_address2 = $fw2->company_address2; $fw3->company_city = $fw2->company_city; $fw3->company_state = $fw2->company_state; $fw3->company_zip_code = $fw2->company_zip_code; $fw3->contact_name = $current_user->getFullName(); $fw3->contact_phone = $current_user->getWorkPhoneExt() != '' ? $current_user->getWorkPhone() . 'x' . $current_user->getWorkPhoneExt() : $current_user->getWorkPhone(); $fw3->contact_email = $current_user->getWorkEmail(); $fw3->kind_of_payer = '941'; $fw3->kind_of_employer = 'none'; //$fw3->third_party_sick_pay = TRUE; if (isset($setup_data['state'][$fw2->company_state]) and isset($setup_data['state'][$fw2->company_state]['state_id']) and $setup_data['state'][$fw2->company_state]['state_id'] != '') { $fw3->state_id1 = $setup_data['state'][$fw2->company_state]['state_id']; } $fw3->lc = count($this->form_data); $fw3->control_number = $fw3->lc + 1; //$fw3->ld = '1234568'; $total_row = Misc::ArrayAssocSum($this->form_data); //Debug::Arr($total_row, 'Total Row Data: ', __FILE__, __LINE__, __METHOD__,10); if (is_array($total_row)) { $fw3->l1 = $total_row['l1']; $fw3->l2 = $total_row['l2']; $fw3->l3 = $total_row['l3']; $fw3->l4 = $total_row['l4']; $fw3->l5 = $total_row['l5']; $fw3->l6 = $total_row['l6']; $fw3->l7 = $total_row['l7']; $fw3->l8 = $total_row['l8']; $fw3->l10 = $total_row['l10']; $fw3->l11 = $total_row['l11']; foreach (range('a', 'z') as $z) { //State income tax if (isset($total_row['l16' . $z])) { $fw3->l16 += $total_row['l16' . $z]; $fw3->l17 += $total_row['l17' . $z]; } //District income tax if (isset($total_row['l18' . $z])) { $fw3->l18 += $total_row['l18' . $z]; $fw3->l19 += $total_row['l19' . $z]; } } } $this->getFormObject()->addForm($fw3); } if ($format == 'efile') { $output_format = 'EFILE'; if ($fw2->getDebug() == TRUE) { $file_name = 'w2_efile_' . date('Y_m_d') . '.csv'; } else { $file_name = 'w2_efile_' . date('Y_m_d') . '.txt'; } $mime_type = 'applications/octet-stream'; //Force file to download. } elseif ($format == 'efile_xml') { $output_format = 'XML'; $file_name = 'w2_efile_' . date('Y_m_d') . '.xml'; $mime_type = 'applications/octet-stream'; //Force file to download. } else { $output_format = 'PDF'; $file_name = $this->file_name; $mime_type = $this->file_mime_type; } $output = $this->getFormObject()->output($output_format); return array('file_name' => $file_name, 'mime_type' => $mime_type, 'data' => $output); }
/** * Get all necessary dates for building the schedule in a single call, this is mainly as a performance optimization. * @param array $data filter data * @return array */ function getScheduleDates($base_date, $type, $strict = TRUE) { $epoch = TTDate::parseDateTime($base_date); if ($epoch == '') { $epoch = TTDate::getTime(); } if ($type == '') { $type = 'week'; } switch (strtolower($type)) { case 'day': if ($strict == TRUE) { $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getEndDayEpoch($epoch); } else { $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); } break; case 'week': if ($strict == TRUE) { $start_date = TTDate::getBeginWeekEpoch($epoch, $this->getCurrentUserPreferenceObject()->getStartWeekDay()); $end_date = TTDate::getEndWeekEpoch($epoch, $this->getCurrentUserPreferenceObject()->getStartWeekDay()); } else { $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 7 * 86400); } break; case 'month': if ($strict == TRUE) { $start_date = TTDate::getBeginWeekEpoch(TTDate::getBeginMonthEpoch($epoch), $this->getCurrentUserPreferenceObject()->getStartWeekDay()); $end_date = TTDate::getEndWeekEpoch(TTDate::getEndMonthEpoch($epoch), $this->getCurrentUserPreferenceObject()->getStartWeekDay()); } else { $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 30 * 86400); } break; case 'year': if ($strict == TRUE) { $start_date = TTDate::getBeginWeekEpoch(TTDate::getBeginMonthEpoch($epoch), $this->getCurrentUserPreferenceObject()->getStartWeekDay()); $end_date = TTDate::getEndWeekEpoch(TTDate::getEndMonthEpoch(TTDate::getEndMonthEpoch($epoch) + 86400 * 2), $this->getCurrentUserPreferenceObject()->getStartWeekDay()); } else { $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 62 * 86400); } break; } $retarr = array('base_date' => $epoch, 'start_date' => $start_date, 'end_date' => $end_date, 'base_display_date' => TTDate::getAPIDate('DATE', $epoch), 'start_display_date' => TTDate::getAPIDate('DATE', $start_date), 'end_display_date' => TTDate::getAPIDate('DATE', $end_date)); Debug::Arr($retarr, 'Schedule Dates: Base Date: ' . $base_date . ' Type: ' . $type . ' Strict: ' . (int) $strict, __FILE__, __LINE__, __METHOD__, 10); return $retarr; }
function _outputPDFForm($format = NULL) { $show_background = TRUE; if ($format == 'pdf_form_print') { $show_background = FALSE; } Debug::Text('Generating Form... Format: ' . $format, __FILE__, __LINE__, __METHOD__, 10); $setup_data = $this->getFormConfig(); $filter_data = $this->getFilterConfig(); //Debug::Arr($filter_data, 'Filter Data: ', __FILE__, __LINE__, __METHOD__,10); $current_company = $this->getUserObject()->getCompanyObject(); if (!is_object($current_company)) { Debug::Text('Invalid company object...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } if ($format == 'efile_xml') { $return940 = $this->getRETURN940Object(); $return940->TaxPeriodEndDate = TTDate::getDate('Y-m-d', TTDate::getEndDayEpoch($filter_data['end_date'])); $return940->ReturnType = ''; $return940->ein = (isset($setup_data['ein']) and $setup_data['ein'] != '') ? $setup_data['ein'] : $current_company->getBusinessNumber(); $return940->BusinessName1 = ''; $return940->BusinessNameControl = ''; $return940->AddressLine = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $return940->City = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $return940->State = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $return940->ZIPCode = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); $this->getFormObject()->addForm($return940); } $f940 = $this->getF940Object(); $f940->setDebug(FALSE); $f940->setShowBackground($show_background); $f940->year = TTDate::getYear($filter_data['end_date']); //Add support for the user to manually set this data in the setup_data. That way they can use multiple tax IDs for different employees, all beit manually. $f940->ein = (isset($setup_data['ein']) and $setup_data['ein'] != '') ? $setup_data['ein'] : $current_company->getBusinessNumber(); $f940->name = (isset($setup_data['name']) and $setup_data['name'] != '') ? $setup_data['name'] : $this->getUserObject()->getFullName(); $f940->trade_name = (isset($setup_data['company_name']) and $setup_data['company_name'] != '') ? $setup_data['company_name'] : $current_company->getName(); $f940->address = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $f940->city = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $f940->state = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $f940->zip_code = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); if (isset($setup_data['return_type']) and is_array($setup_data['return_type'])) { $return_type_arr = array(); foreach ($setup_data['return_type'] as $return_type) { switch ($return_type) { case 10: //Amended $return_type_arr[] = 'a'; break; case 20: //Successor $return_type_arr[] = 'b'; break; case 30: //No Payments $return_type_arr[] = 'c'; break; case 40: //Final $return_type_arr[] = 'd'; break; } } $f940->return_type = $return_type_arr; } if (isset($setup_data['state_id'])) { if ($setup_data['state_id'] === 0 or $setup_data['state_id'] == '00' or $setup_data['state_id'] == '') { $f940->l1b = TRUE; //Let them set this manually. } else { if (strlen($setup_data['state_id']) == 2) { $f940->l1a = $setup_data['state_id']; } } } //Exempt payment check boxes if (isset($setup_data['exempt_payment']) and is_array($setup_data['exempt_payment'])) { foreach ($setup_data['exempt_payment'] as $return_type) { switch ($return_type) { case 10: //Fringe $f940->l4a = TRUE; break; case 20: //Group life insurance $f940->l4b = TRUE; break; case 30: //Retirement/Pension $f940->l4c = TRUE; break; case 40: //Dependant care $f940->l4d = TRUE; break; case 50: //Other $f940->l4e = TRUE; break; } } } //Debug::Arr($this->form_data['quarter'], 'Final Data for Form: ', __FILE__, __LINE__, __METHOD__,10); if (isset($this->form_data) and count($this->form_data) == 3) { $f940->l3 = $this->form_data['total']['total_payments']; $f940->l4 = $this->form_data['total']['exempt_payments']; $f940->l5 = $this->form_data['total']['excess_payments']; $f940->l10 = $setup_data['line_10']; $f940->l11 = $setup_data['line_11']; $f940->l13 = $setup_data['tax_deposited']; $f940->l15b = TRUE; if (isset($this->form_data['quarter'][1]['after_adjustment_tax'])) { $f940->l16a = $this->form_data['quarter'][1]['after_adjustment_tax']; } if (isset($this->form_data['quarter'][2]['after_adjustment_tax'])) { $f940->l16b = $this->form_data['quarter'][2]['after_adjustment_tax']; } if (isset($this->form_data['quarter'][3]['after_adjustment_tax'])) { $f940->l16c = $this->form_data['quarter'][3]['after_adjustment_tax']; } if (isset($this->form_data['quarter'][4]['after_adjustment_tax'])) { $f940->l16d = $this->form_data['quarter'][4]['after_adjustment_tax']; } } else { Debug::Arr($this->data, 'Invalid Form Data: ', __FILE__, __LINE__, __METHOD__, 10); } $this->getFormObject()->addForm($f940); if (isset($f940sb) and is_object($f940sb)) { $this->getFormObject()->addForm($f940sb); } if ($format == 'efile_xml') { $output_format = 'XML'; $file_name = '940_efile_' . date('Y_m_d') . '.xml'; $mime_type = 'applications/octet-stream'; //Force file to download. } else { $output_format = 'PDF'; $file_name = $this->file_name; $mime_type = $this->file_mime_type; } $output = $this->getFormObject()->output($output_format); return $output; }
function createPayStubAmendments($epoch = NULL) { //Get all recurring pay stub amendments and generate single pay stub amendments if appropriate. if ($epoch == '') { $epoch = TTDate::getTime(); } $ulf = TTnew('UserListFactory'); Debug::text('Recurring PS Amendment ID: ' . $this->getId() . ' Frequency: ' . $this->getFrequency(), __FILE__, __LINE__, __METHOD__, 10); $this->StartTransaction(); $tmp_user_ids = $this->getUser(); if ($tmp_user_ids[0] == -1) { $ulf->getByCompanyIdAndStatus($this->getCompany(), 10); foreach ($ulf as $user_obj) { $user_ids[] = $user_obj->getId(); } unset($user_obj); } else { $user_ids = $this->getUser(); } unset($tmp_user_ids); Debug::text('Total User IDs: ' . count($user_ids), __FILE__, __LINE__, __METHOD__, 10); if (is_array($user_ids) and count($user_ids) > 0) { //Make the PS amendment duplicate check start/end date separate //Make the PS amendment effective date separate. switch ($this->getFrequency()) { case 10: //Get all open pay periods $pplf = TTnew('PayPeriodListFactory'); //FIXME: Get all non-closed pay periods AFTER the start date. $pplf->getByUserIdListAndNotStatusAndStartDateAndEndDate($user_ids, 20, $this->getStartDate(), $this->getEndDate()); //All non-closed pay periods Debug::text('Found Open Pay Periods: ' . $pplf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); foreach ($pplf as $pay_period_obj) { Debug::text('Working on Pay Period: ' . $pay_period_obj->getId(), __FILE__, __LINE__, __METHOD__, 10); //If near the end of a pay period, or a pay period is already ended, add PS amendment if //it does not already exist. if ($epoch >= $pay_period_obj->getEndDate() and $this->checkTimeFrame($epoch)) { Debug::text('After end of pay period. Start Date: ' . TTDate::getDate('DATE+TIME', $pay_period_obj->getStartDate()) . ' End Date: ' . TTDate::getDate('DATE+TIME', $pay_period_obj->getEndDate()), __FILE__, __LINE__, __METHOD__, 10); $psalf = TTnew('PayStubAmendmentListFactory'); //Loop through each user of this Pay Period Schedule adding PS amendments if they don't already exist. $pay_period_schedule_users = $pay_period_obj->getPayPeriodScheduleObject()->getUser(); Debug::text(' Pay Period Schedule Users: ' . count($pay_period_schedule_users), __FILE__, __LINE__, __METHOD__, 10); foreach ($pay_period_schedule_users as $user_id) { //Make sure schedule user is in the PS amendment user list and user is active. Debug::text(' Pay Period Schedule User: '******' Recurring PS Amendment Selected Users: ', __FILE__, __LINE__, __METHOD__,10); if ($ulf->getById($user_id)->getCurrent()->getStatus() == 10 and in_array($user_id, $user_ids)) { //Check to see if the amendment was added already. if ($psalf->getByUserIdAndRecurringPayStubAmendmentIdAndStartDateAndEndDate($user_id, $this->getId(), $pay_period_obj->getStartDate(), $pay_period_obj->getEndDate())->getRecordCount() == 0) { //No amendment, good to insert one Debug::text('Inserting Recurring PS Amendment for User: '******'PayStubAmendmentFactory'); $psaf->setUser($user_id); $psaf->setStatus(50); $psaf->setType($this->getType()); $psaf->setRecurringPayStubAmendmentId($this->getId()); $psaf->setPayStubEntryNameId($this->getPayStubEntryNameId()); if ($this->getType() == 10) { $psaf->setRate($this->getRate()); $psaf->setUnits($this->getUnits()); $psaf->setAmount($this->getAmount()); } else { $psaf->setPercentAmount($this->getPercentAmount()); $psaf->setPercentAmountEntryNameID($this->getPercentAmountEntryNameId()); } $psaf->setDescription($this->getPayStubAmendmentDescription()); $psaf->setEffectiveDate(TTDate::getBeginDayEpoch($pay_period_obj->getEndDate())); if ($psaf->isValid()) { $psaf->Save(); } } else { //Amendment already inserted! Debug::text('Recurring PS Amendment already inserted for User: '******'Skipping User because they are INACTIVE or are not on the Recurring PS Amendment User List - ID: ' . $user_id, __FILE__, __LINE__, __METHOD__, 10); //continue; } } } else { Debug::text('Not in TimeFrame, not inserting amendments: Epoch: ' . $epoch . ' Pay Period End Date: ' . $pay_period_obj->getEndDate(), __FILE__, __LINE__, __METHOD__, 10); } } break; case 30: //Weekly //Weekly case 40: //Monthly //Monthly case 70: //Annually switch ($this->getFrequency()) { case 30: $trigger_date = TTDate::getDateOfNextDayOfWeek(TTDate::getBeginWeekEpoch($epoch), $this->getStartDate()); $start_date = TTDate::getBeginWeekEpoch($epoch); $end_date = TTDate::getEndWeekEpoch($epoch); break; case 40: $trigger_date = TTDate::getDateOfNextDayOfMonth(TTDate::getBeginMonthEpoch($epoch), $this->getStartDate()); //$monthly_date = TTDate::getDateOfNextDayOfMonth( TTDate::getBeginMonthEpoch($epoch), $this->getStartDate() ); $start_date = TTDate::getBeginMonthEpoch($epoch); $end_date = TTDate::getEndMonthEpoch($epoch); break; case 70: $trigger_date = TTDate::getDateOfNextYear($this->getStartDate(), $epoch); //$start_date = TTDate::getBeginYearEpoch($epoch); //$end_date = TTDate::getEndYearEpoch($epoch); $start_date = TTDate::getBeginDayEpoch($epoch - 86400 * 365); $end_date = TTDate::getEndDayEpoch($epoch); break; } Debug::text('Trigger Date: ' . TTDate::getDate('DATE', $trigger_date), __FILE__, __LINE__, __METHOD__, 10); if ($epoch >= $trigger_date and $this->checkTimeFrame($epoch)) { Debug::text('Within timeframe... Start Date: ' . TTDate::getDate('DATE+TIME', $start_date) . ' End Date: ' . TTDate::getDate('DATE+TIME', $end_date), __FILE__, __LINE__, __METHOD__, 10); foreach ($user_ids as $user_id) { //Make sure schedule user is in the PS amendment user list and user is active. if ($ulf->getById($user_id)->getCurrent()->getStatus() != 10 and !in_array($user_id, $user_ids)) { Debug::text('Skipping User because they are INACTIVE or are not on the Recurring PS Amendment User List - ID: ' . $user_id, __FILE__, __LINE__, __METHOD__, 10); continue; } $psalf = TTnew('PayStubAmendmentListFactory'); if ($psalf->getByUserIdAndRecurringPayStubAmendmentIdAndStartDateAndEndDate($user_id, $this->getId(), $start_date, $end_date)->getRecordCount() == 0) { //No amendment, good to insert one Debug::text('Inserting Recurring PS Amendment for User: '******'PayStubAmendmentFactory'); $psaf->setUser($user_id); $psaf->setStatus(50); $psaf->setType($this->getType()); $psaf->setRecurringPayStubAmendmentId($this->getId()); $psaf->setPayStubEntryNameId($this->getPayStubEntryNameId()); if ($this->getType() == 10) { $psaf->setRate($this->getRate()); $psaf->setUnits($this->getUnits()); $psaf->setAmount($this->getAmount()); } else { $psaf->setPercentAmount($this->getPercentAmount()); $psaf->setPercentAmountEntryNameID($this->getPercentAmountEntryNameId()); } $psaf->setDescription($this->getDescription()); $psaf->setEffectiveDate(TTDate::getBeginDayEpoch($trigger_date)); if ($psaf->isValid()) { $psaf->Save(); } } else { //Amendment already inserted! Debug::text('Recurring PS Amendment already inserted for User: ' . $user_id, __FILE__, __LINE__, __METHOD__, 10); } } } break; } } //$this->FailTransaction(); $this->CommitTransaction(); return TRUE; }
function Validate() { Debug::text('Validating...', __FILE__, __LINE__, __METHOD__, 10); //Call this here so getShiftData can get the correct total time, before we call findUserDate. if ($this->getEnableCalcTotalTime() == TRUE) { $this->calcTotalTime(); } if (is_object($this->getPunchObject())) { $this->findUserDate(); } Debug::text('User Date Id: ' . $this->getUserDateID(), __FILE__, __LINE__, __METHOD__, 10); //Don't check for a valid pay period here, do that in PunchFactory->Validate(), as we need to allow users to delete punches that were created outside pay periods in legacy versions. if ($this->getDeleted() == FALSE and $this->getUserDateObject() == FALSE) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Date/Time is incorrect, or pay period does not exist for this date. Please create a pay period schedule and assign this employee to it if you have not done so already')); } elseif (is_object($this->getUserDateObject()) and is_object($this->getUserDateObject()->getPayPeriodObject()) and $this->getUserDateObject()->getPayPeriodObject()->getIsLocked() == TRUE) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Pay Period is Currently Locked')); } //Make sure the user isn't entering punches before the employees hire or after termination date, as its likely they wouldn't have a wage //set for that anyways and wouldn't get paid for it. if ($this->getDeleted() == FALSE and (is_object($this->getPunchObject()) and $this->getPunchObject()->getDeleted() == FALSE) and is_object($this->getUserDateObject()) and is_object($this->getUserDateObject()->getUserObject())) { if ($this->getUserDateObject()->getUserObject()->getHireDate() != '' and TTDate::getBeginDayEpoch($this->getUserDateObject()->getDateStamp()) < TTDate::getBeginDayEpoch($this->getUserDateObject()->getUserObject()->getHireDate())) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Punch is before employees hire date')); } if ($this->getUserDateObject()->getUserObject()->getTerminationDate() != '' and TTDate::getEndDayEpoch($this->getUserDateObject()->getDateStamp()) > TTDate::getEndDayEpoch($this->getUserDateObject()->getUserObject()->getTerminationDate())) { $this->Validator->isTRUE('date_stamp', FALSE, TTi18n::gettext('Punch is after employees termination date')); } } //Skip these checks if they are deleting a punch. if (is_object($this->getPunchObject()) and $this->getPunchObject()->getDeleted() == FALSE) { $plf = $this->getPLFByPunchControlID(); if ($plf !== NULL and ($this->isNew() and $plf->getRecordCount() == 2 or $plf->getRecordCount() > 2)) { //TTi18n::gettext('Punch Control can not have more than two punches. Please use the Add Punch button instead') //They might be trying to insert a punch inbetween two others? $this->Validator->isTRUE('punch_control', FALSE, TTi18n::gettext('Time conflicts with another punch on this day (c)')); } //Sometimes shift data won't return all the punches to proper check for conflicting punches. //So we need to make sure other punches assigned to this punch_control record are proper. //This fixes the bug of having shifts: 2:00AM Lunch Out, 2:30AM Lunch In, 6:00AM Out, 10:00PM In (in that order), then trying to move the 10PM punch to the open IN slot before the 2AM punch. if ($plf->getRecordCount() > 0) { foreach ($plf as $p_obj) { if ($p_obj->getID() != $this->getPunchObject()->getID()) { if ($this->getPunchObject()->getStatus() == 10 and $p_obj->getStatus() == 10 and $this->getPunchObject()->getTimeStamp() > $p_obj->getTimeStamp()) { //Make sure we match on status==10 for both sides, otherwise this fails to catch the problem case. $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('In punches cannot occur after an out punch, in the same punch pair (a)')); } elseif ($this->getPunchObject()->getStatus() == 20 and $p_obj->getStatus() == 10 and $this->getPunchObject()->getTimeStamp() < $p_obj->getTimeStamp()) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Out punches cannot occur before an in punch, in the same punch pair (a)')); } } } } unset($p_obj); if ($this->Validator->isValid() == TRUE) { //Don't bother checking these resource intensive issues if there are already validation errors. $shift_data = $this->getShiftData(); if (is_array($shift_data) and $this->Validator->hasError('time_stamp') == FALSE) { foreach ($shift_data['punches'] as $punch_data) { //Make sure there aren't two In punches, or two Out punches in the same pair. //This fixes the bug where if you have an In punch, then click the blank cell below it //to add a new punch, but change the status from Out to In instead. if (isset($punches[$punch_data['punch_control_id']][$punch_data['status_id']])) { if ($punch_data['status_id'] == 10) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('In punches cannot occur twice in the same punch pair, you may want to make this an out punch instead')); } else { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Out punches cannot occur twice in the same punch pair, you may want to make this an in punch instead')); } } //Debug::text(' Current Punch Object: ID: '. $this->getPunchObject()->getId() .' TimeStamp: '. $this->getPunchObject()->getTimeStamp() .' Status: '. $this->getPunchObject()->getStatus(), __FILE__, __LINE__, __METHOD__,10); //Debug::text(' Looping Punch Object: ID: '. $punch_data['id'] .' TimeStamp: '. $punch_data['time_stamp'] .' Status: '.$punch_data['status_id'], __FILE__, __LINE__, __METHOD__,10); //Check for another punch that matches the timestamp and status. if ($this->getPunchObject()->getID() != $punch_data['id']) { if ($this->getPunchObject()->getTimeStamp() == $punch_data['time_stamp'] and $this->getPunchObject()->getStatus() == $punch_data['status_id']) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Time and status match that of another punch, this could be due to rounding') . ' (' . TTDate::getDate('DATE+TIME', $punch_data['time_stamp']) . ')'); break; //Break the loop on validation error, so we don't get multiple errors that may be confusing. } } //Check for another punch that matches the timestamp and NOT status in the SAME punch pair. if ($this->getPunchObject()->getID() != $punch_data['id'] and $this->getID() == $punch_data['punch_control_id']) { if ($this->getPunchObject()->getTimeStamp() == $punch_data['time_stamp'] and $this->getPunchObject()->getStatus() != $punch_data['status_id']) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Time matches another punch in the same punch pair, this could be due to rounding') . ' (' . TTDate::getDate('DATE+TIME', $punch_data['time_stamp']) . ')'); break; //Break the loop on validation error, so we don't get multiple errors that may be confusing. } } $punches[$punch_data['punch_control_id']][$punch_data['status_id']] = $punch_data; } unset($punch_data); if (isset($punches[$this->getID()])) { Debug::text('Current Punch ID: ' . $this->getPunchObject()->getId() . ' Punch Control ID: ' . $this->getID() . ' Status: ' . $this->getPunchObject()->getStatus(), __FILE__, __LINE__, __METHOD__, 10); //Debug::Arr($punches, 'Punches Arr: ', __FILE__, __LINE__, __METHOD__,10); if ($this->getPunchObject()->getStatus() == 10 and isset($punches[$this->getID()][20]) and $this->getPunchObject()->getTimeStamp() > $punches[$this->getID()][20]['time_stamp']) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('In punches cannot occur after an out punch, in the same punch pair')); } elseif ($this->getPunchObject()->getStatus() == 20 and isset($punches[$this->getID()][10]) and $this->getPunchObject()->getTimeStamp() < $punches[$this->getID()][10]['time_stamp']) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Out punches cannot occur before an in punch, in the same punch pair')); } else { Debug::text('bPunch does not match any other punch pair.', __FILE__, __LINE__, __METHOD__, 10); $punch_neighbors = Misc::getArrayNeighbors($punches, $this->getID(), 'both'); //Debug::Arr($punch_neighbors, ' Punch Neighbors: ', __FILE__, __LINE__, __METHOD__,10); if (isset($punch_neighbors['next']) and isset($punches[$punch_neighbors['next']])) { Debug::text('Found Next Punch...', __FILE__, __LINE__, __METHOD__, 10); if (isset($punches[$punch_neighbors['next']][10]) and $this->getPunchObject()->getTimeStamp() > $punches[$punch_neighbors['next']][10]['time_stamp'] or isset($punches[$punch_neighbors['next']][20]) and $this->getPunchObject()->getTimeStamp() > $punches[$punch_neighbors['next']][20]['time_stamp']) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Time conflicts with another punch on this day') . ' (a)'); } } if (isset($punch_neighbors['prev']) and isset($punches[$punch_neighbors['prev']])) { Debug::text('Found prev Punch...', __FILE__, __LINE__, __METHOD__, 10); //This needs to take into account DST. Specifically if punches are like this: //03-Nov-12: IN: 10:00PM //04-Nov-12: OUT: 1:00AM L //04-Nov-12: IN: 1:30AM L //04-Nov-12: OUT: 6:30AM L //Since the 1AM to 2AM occur twice due to the "fall back" DST change, we need to allow those punches to be entered. if (isset($punches[$punch_neighbors['prev']][10]) and ($this->getPunchObject()->getTimeStamp() < $punches[$punch_neighbors['prev']][10]['time_stamp'] and TTDate::doesRangeSpanDST($this->getPunchObject()->getTimeStamp(), $punches[$punch_neighbors['prev']][10]['time_stamp']) == FALSE) or isset($punches[$punch_neighbors['prev']][20]) and ($this->getPunchObject()->getTimeStamp() < $punches[$punch_neighbors['prev']][20]['time_stamp'] and TTDate::doesRangeSpanDST($this->getPunchObject()->getTimeStamp(), $punches[$punch_neighbors['prev']][20]['time_stamp']) == FALSE)) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Time conflicts with another punch on this day') . ' (b)'); } } } //Check to make sure punches don't exceed maximum shift time. $maximum_shift_time = $plf->getPayPeriodMaximumShiftTime($this->getPunchObject()->getUser()); Debug::text('Maximum shift time: ' . $maximum_shift_time, __FILE__, __LINE__, __METHOD__, 10); if ($shift_data['total_time'] > $maximum_shift_time) { $this->Validator->isTRUE('time_stamp', FALSE, TTi18n::gettext('Punch exceeds maximum shift time of') . ' ' . TTDate::getTimeUnit($maximum_shift_time) . ' ' . TTi18n::getText('hrs set for this pay period schedule')); } } unset($punches); } } } if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $this->getEnableStrictJobValidation() == TRUE) { if ($this->getJob() > 0) { $jlf = TTnew('JobListFactory'); $jlf->getById($this->getJob()); if ($jlf->getRecordCount() > 0) { $j_obj = $jlf->getCurrent(); if (is_object($this->getUserDateObject()) and $j_obj->isAllowedUser($this->getUserDateObject()->getUser()) == FALSE) { $this->Validator->isTRUE('job', FALSE, TTi18n::gettext('Employee is not assigned to this job')); } if ($j_obj->isAllowedItem($this->getJobItem()) == FALSE) { $this->Validator->isTRUE('job_item', FALSE, TTi18n::gettext('Task is not assigned to this job')); } } } } return TRUE; }
function _outputPDFForm($format = NULL) { $show_background = TRUE; if ($format == 'pdf_form_print') { $show_background = FALSE; } Debug::Text('Generating Form... Format: ' . $format, __FILE__, __LINE__, __METHOD__, 10); $setup_data = $this->getFormConfig(); $filter_data = $this->getFilterConfig(); //Debug::Arr($filter_data, 'Filter Data: ', __FILE__, __LINE__, __METHOD__,10); $current_company = $this->getUserObject()->getCompanyObject(); if (!is_object($current_company)) { Debug::Text('Invalid company object...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } if ($format == 'efile_xml') { $return941 = $this->getRETURN941Object(); $return941->TaxPeriodEndDate = TTDate::getDate('Y-m-d', TTDate::getEndDayEpoch($filter_data['end_date'])); $return941->ReturnType = ''; $return941->ein = (isset($setup_data['ein']) and $setup_data['ein'] != '') ? $setup_data['ein'] : $current_company->getBusinessNumber(); $return941->BusinessName1 = ''; $return941->BusinessNameControl = ''; $return941->AddressLine = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $return941->City = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $return941->State = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $return941->ZIPCode = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); $this->getFormObject()->addForm($return941); } $f941 = $this->getF941Object(); $f941->setDebug(FALSE); $f941->setShowBackground($show_background); $f941->year = TTDate::getYear($filter_data['end_date']); //Add support for the user to manually set this data in the setup_data. That way they can use multiple tax IDs for different employees, all beit manually. $f941->ein = (isset($setup_data['ein']) and $setup_data['ein'] != '') ? $setup_data['ein'] : $current_company->getBusinessNumber(); $f941->name = (isset($setup_data['name']) and $setup_data['name'] != '') ? $setup_data['name'] : $this->getUserObject()->getFullName(); $f941->trade_name = (isset($setup_data['company_name']) and $setup_data['company_name'] != '') ? $setup_data['company_name'] : $current_company->getName(); $f941->address = (isset($setup_data['address1']) and $setup_data['address1'] != '') ? $setup_data['address1'] : $current_company->getAddress1() . ' ' . $current_company->getAddress2(); $f941->city = (isset($setup_data['city']) and $setup_data['city'] != '') ? $setup_data['city'] : $current_company->getCity(); $f941->state = (isset($setup_data['province']) and ($setup_data['province'] != '' and $setup_data['province'] != 0)) ? $setup_data['province'] : $current_company->getProvince(); $f941->zip_code = (isset($setup_data['postal_code']) and $setup_data['postal_code'] != '') ? $setup_data['postal_code'] : $current_company->getPostalCode(); $f941->quarter = TTDate::getYearQuarter($filter_data['end_date']); //Debug::Arr($this->form_data, 'Final Data for Form: ', __FILE__, __LINE__, __METHOD__,10); if (isset($this->form_data) and count($this->form_data) == 3) { $f941->l1 = count($this->user_ids); $f941->l2 = $this->form_data['total']['l2']; $f941->l3 = $this->form_data['total']['l3']; $f941->l5a = $this->form_data['total']['l5a']; $f941->l5b = $this->form_data['total']['l5b']; $f941->l5c = $this->form_data['total']['l5c']; $f941->l5d = $this->form_data['total']['l5d']; if (isset($setup_data['quarter_deposit']) and $setup_data['quarter_deposit'] != '') { $f941->l11 = Misc::MoneyFormat($setup_data['quarter_deposit'], FALSE); } //Debug::Text('L11: '. $f941->l11 .' L6: '. $f941->calcL6() .' - '. $this->form_data['total']['l10'] , __FILE__, __LINE__, __METHOD__,10); $f941->l15b = TRUE; if (isset($setup_data['deposit_schedule']) and $setup_data['deposit_schedule'] == 10) { if (isset($this->form_data['quarter'][1]['l10'])) { $f941->l16_month1 = $this->form_data['quarter'][1]['l10']; } if (isset($this->form_data['quarter'][2]['l10'])) { $f941->l16_month2 = $this->form_data['quarter'][2]['l10']; } if (isset($this->form_data['quarter'][3]['l10'])) { $f941->l16_month3 = $this->form_data['quarter'][3]['l10']; } } elseif (isset($setup_data['deposit_schedule']) and $setup_data['deposit_schedule'] == 20) { $f941sb = $this->getFormObject()->getFormObject('941sb', 'US'); $f941sb->setShowBackground($show_background); $f941sb->year = $f941->year; $f941sb->ein = $f941->ein; $f941sb->name = $f941->name; $f941sb->quarter = $f941->quarter; for ($i = 1; $i <= 3; $i++) { if (isset($this->form_data['pay_period'][$i])) { foreach ($this->form_data['pay_period'][$i] as $pay_period_epoch => $data) { //Debug::Text('SB: Month: '. $i .' Pay Period Date: '. TTDate::getDate('DATE', $pay_period_epoch) .' DOM: '. TTDate::getDayOfMonth($pay_period_epoch) .' Amount: '. $data['l10'], __FILE__, __LINE__, __METHOD__,10); $f941sb_data[$i][TTDate::getDayOfMonth($pay_period_epoch)] = $data['l10']; //Don't round this as it can cause mismatches in the totals. } } } if (isset($f941sb_data[1])) { $f941sb->month1 = $f941sb_data[1]; } if (isset($f941sb_data[2])) { $f941sb->month2 = $f941sb_data[2]; } if (isset($f941sb_data[3])) { $f941sb->month3 = $f941sb_data[3]; } unset($i, $d, $f941sb_data); } } else { Debug::Arr($this->data, 'Invalid Form Data: ', __FILE__, __LINE__, __METHOD__, 10); } $this->getFormObject()->addForm($f941); if (isset($f941sb) and is_object($f941sb)) { $this->getFormObject()->addForm($f941sb); } if ($format == 'efile_xml') { $output_format = 'XML'; $file_name = '941_efile_' . date('Y_m_d') . '.xml'; $mime_type = 'applications/octet-stream'; //Force file to download. } else { $output_format = 'PDF'; $file_name = $this->file_name; $mime_type = $this->file_mime_type; } $output = $this->getFormObject()->output($output_format); return $output; }
function convertTimePeriodToStartEndDate($time_period_arr, $prefix = NULL) { Debug::Arr($time_period_arr, 'Input: Time Period Array: ', __FILE__, __LINE__, __METHOD__, 10); //Convert time_period into start/end date, with pay_period_schedule_ids if necessary. if (isset($time_period_arr['time_period']) and ($time_period_arr['time_period'] == 'custom_date' or $time_period_arr['time_period'] == 'custom_time')) { Debug::Text('Found Custom dates...', __FILE__, __LINE__, __METHOD__, 10); $retarr[$prefix . 'time_period']['time_period'] = $time_period_arr['time_period']; if (isset($time_period_arr['start_date'])) { $retarr[$prefix . 'start_date'] = TTDate::getBeginDayEpoch(TTDate::parseDateTime($time_period_arr['start_date'])); } if (isset($time_period_arr['end_date'])) { $retarr[$prefix . 'end_date'] = TTDate::getEndDayEpoch(TTDate::parseDateTime($time_period_arr['end_date'])); } } elseif (isset($time_period_arr['time_period'])) { $params = array(); if (isset($time_period_arr['pay_period_schedule_id'])) { $params = array('pay_period_schedule_id' => $time_period_arr['pay_period_schedule_id']); //Make sure we keep the original array intact so we if this function is run more than once it will work each time. $retarr[$prefix . 'time_period']['pay_period_schedule_id'] = $time_period_arr['pay_period_schedule_id']; } elseif (isset($time_period_arr['pay_period_id'])) { $params = array('pay_period_id' => $time_period_arr['pay_period_id']); //Make sure we keep the original array intact so we if this function is run more than once it will work each time. $retarr[$prefix . 'time_period']['pay_period_id'] = $time_period_arr['pay_period_id']; } if (!isset($time_period_arr['time_period'])) { Debug::Text('ERROR: Time Period idenfier not specified!', __FILE__, __LINE__, __METHOD__, 10); $retarr[$prefix . 'time_period'] = NULL; } else { $retarr[$prefix . 'time_period']['time_period'] = $time_period_arr['time_period']; } //Debug::Arr($params, 'Time Period: '.$time_period_arr['time_period'] .' Params: ', __FILE__, __LINE__, __METHOD__,10); $time_period_dates = TTDate::getTimePeriodDates($time_period_arr['time_period'], NULL, $this->getUserObject(), $params); if ($time_period_dates != FALSE) { if (isset($time_period_dates['start_date'])) { $retarr[$prefix . 'start_date'] = $time_period_dates['start_date']; } if (isset($time_period_dates['end_date'])) { $retarr[$prefix . 'end_date'] = $time_period_dates['end_date']; } if (isset($time_period_dates['pay_period_id'])) { $retarr[$prefix . 'pay_period_id'] = $time_period_dates['pay_period_id']; } } else { //No pay period find default to no time period, otherwise the report can take forever to finish. Debug::Text('No pay periods found, defaulting to none (0)...', __FILE__, __LINE__, __METHOD__, 10); $retarr[$prefix . 'pay_period_id'] = 0; //This can actually find data not assigned to a pay period. } } else { Debug::Text('Invalid TimePeriod filter...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } Debug::Arr($retarr, 'Output: Time Period Array: ', __FILE__, __LINE__, __METHOD__, 10); return $retarr; }
function getPartialPunchTotalTime($in_epoch, $out_epoch, $total_time, $user_id) { $retval = $total_time; if ($this->isActiveTime($in_epoch, $out_epoch, $user_id) and $this->getIncludePartialPunch() == TRUE and ($this->getStartTime() > 0 or $this->getEndTime() > 0)) { Debug::text(' Checking for Active Time with: In: ' . TTDate::getDate('DATE+TIME', $in_epoch) . ' Out: ' . TTDate::getDate('DATE+TIME', $out_epoch), __FILE__, __LINE__, __METHOD__, 10); Debug::text(' Raw Start TimeStamp(' . $this->getStartTime(TRUE) . '): ' . TTDate::getDate('DATE+TIME', $this->getStartTime()) . ' Raw End TimeStamp(' . $this->getEndTime(TRUE) . '): ' . TTDate::getDate('DATE+TIME', $this->getEndTime()), __FILE__, __LINE__, __METHOD__, 10); $start_time_stamp = TTDate::getTimeLockedDate($this->getStartTime(), $in_epoch); $end_time_stamp = TTDate::getTimeLockedDate($this->getEndTime(), $in_epoch); //Check if end timestamp is before start, if it is, move end timestamp to next day. if ($end_time_stamp < $start_time_stamp) { Debug::text(' Moving End TimeStamp to next day.', __FILE__, __LINE__, __METHOD__, 10); $end_time_stamp = TTDate::getTimeLockedDate($this->getEndTime(), $end_time_stamp + 86400); } //Handle the last second of the day, so punches that span midnight like 11:00PM to 6:00AM get a full 1 hour for the time before midnight, rather than 59mins and 59secs. if (TTDate::getHour($end_time_stamp) == 23 and TTDate::getMinute($end_time_stamp) == 59) { $end_time_stamp = TTDate::getEndDayEpoch($end_time_stamp) + 1; Debug::text(' End time stamp is within the last minute of day, make sure we include the last second of the day as well.', __FILE__, __LINE__, __METHOD__, 10); } $retval = 0; for ($i = $start_time_stamp - 86400; $i <= $end_time_stamp + 86400; $i += 86400) { //Due to DST, we need to make sure we always lock time of day so its the exact same. Without this it can walk by one hour either way. $tmp_start_time_stamp = TTDate::getTimeLockedDate($this->getStartTime(), $i); $tmp_end_time_stamp = TTDate::getTimeLockedDate($end_time_stamp, $tmp_start_time_stamp + ($end_time_stamp - $start_time_stamp)); //Use $end_time_stamp as it can be modified above due to being near midnight if ($this->isActiveTime($tmp_start_time_stamp, $tmp_end_time_stamp, $user_id) == TRUE) { $retval += TTDate::getTimeOverLapDifference($tmp_start_time_stamp, $tmp_end_time_stamp, $in_epoch, $out_epoch); Debug::text(' Calculating partial time against Start TimeStamp: ' . TTDate::getDate('DATE+TIME', $tmp_start_time_stamp) . ' End TimeStamp: ' . TTDate::getDate('DATE+TIME', $tmp_end_time_stamp) . ' Total: ' . $retval, __FILE__, __LINE__, __METHOD__, 10); } else { Debug::text(' Not Active on this day: ' . TTDate::getDate('DATE+TIME', $i), __FILE__, __LINE__, __METHOD__, 10); } } } Debug::text(' Partial Punch Total Time: ' . $retval, __FILE__, __LINE__, __METHOD__, 10); return $retval; }
function calculate($epoch = NULL) { if ($this->getUserObject() == FALSE) { return FALSE; } if ($this->getPayPeriodObject() == FALSE) { return FALSE; } if ($epoch == NULL or $epoch == '') { $epoch = TTDate::getTime(); } //Use User Termination Date instead of ROE. if ($this->getUserObject()->getTerminationDate() != '' and $this->getUserObject()->getTerminationDate() >= $this->getPayPeriodObject()->getStartDate() and $this->getUserObject()->getTerminationDate() <= $this->getPayPeriodObject()->getEndDate()) { Debug::text('User has been terminated in this pay period!', __FILE__, __LINE__, __METHOD__, 10); $is_terminated = TRUE; } else { $is_terminated = FALSE; } //Allow generating pay stubs for employees who have any status, but if its not ID=10 //Then the termination date must fall within the start/end date of the pay period, or after the end date (if its the current pay period) //The idea here is to allow employees to be marked terminated (or on leave) and still get their previous or final pay stub generated. //Also allow pay stubs to be generated in pay periods *before* their termination date. if ($this->getUserObject()->getStatus() != 10 and ($is_terminated == FALSE and ($this->getUserObject()->getTerminationDate() == '' or $this->getUserObject()->getTerminationDate() < $this->getPayPeriodObject()->getStartDate()))) { Debug::text('Pay Period is after users termination date (' . $this->getUserObject()->getTerminationDate() . '), or no termination date is set...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } Debug::text('User Id: ' . $this->getUser() . ' Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $this->getPayPeriodObject()->getEndDate()), __FILE__, __LINE__, __METHOD__, 10); $generic_queue_status_label = $this->getUserObject()->getFullName(TRUE) . ' - ' . TTi18n::gettext('Pay Stub'); $pay_stub = TTnew('PayStubFactory'); $pay_stub->StartTransaction(); $old_pay_stub_id = NULL; if ($this->getEnableCorrection() == TRUE) { Debug::text('Correction Enabled!', __FILE__, __LINE__, __METHOD__, 10); $pay_stub->setTemp(TRUE); //Check for current pay stub ID so we can compare against it. $pslf = TTnew('PayStubListFactory'); $pslf->getByUserIdAndPayPeriodId($this->getUser(), $this->getPayPeriod()); if ($pslf->getRecordCount() > 0) { $old_pay_stub_id = $pslf->getCurrent()->getId(); Debug::text('Comparing Against Pay Stub ID: ' . $old_pay_stub_id, __FILE__, __LINE__, __METHOD__, 10); } } $pay_stub->setUser($this->getUser()); $pay_stub->setPayPeriod($this->getPayPeriod()); $pay_stub->setCurrency($this->getUserObject()->getCurrency()); $pay_stub->setStatus(10); //New if ($is_terminated == TRUE) { Debug::text('User is Terminated, assuming final pay, setting End Date to terminated date: ' . TTDate::getDate('DATE+TIME', $this->getUserObject()->getTerminationDate()), __FILE__, __LINE__, __METHOD__, 10); $pay_stub->setStartDate($pay_stub->getPayPeriodObject()->getStartDate()); $pay_stub->setEndDate($this->getUserObject()->getTerminationDate()); //Use the PS generation date instead of terminated date... //Unlikely they would pay someone before the pay stub is generated. //Perhaps still use the pay period transaction date for this too? //Anything we set won't be correct for everyone. Maybe a later date is better though? //Perhaps add to the user factory under Termination Date a: "Final Transaction Date" for this purpose? //Use the end of the current date for the transaction date, as if the employee is terminated //on the same day they are generating the pay stub, the transaction date could be before the end date //as the end date is at 11:59PM //For now make sure that the transaction date for a terminated employee is never before their termination date. if (TTDate::getEndDayEpoch(TTDate::getTime()) < $this->getUserObject()->getTerminationDate()) { $pay_stub->setTransactionDate($this->getUserObject()->getTerminationDate()); } else { $pay_stub->setTransactionDate(TTDate::getEndDayEpoch(TTDate::getTime())); } } else { Debug::text('User Termination Date is NOT set, assuming normal pay.', __FILE__, __LINE__, __METHOD__, 10); $pay_stub->setDefaultDates(); } //This must go after setting advance if ($this->getEnableCorrection() == FALSE and $pay_stub->IsUniquePayStub() == FALSE) { Debug::text('Pay Stub already exists', __FILE__, __LINE__, __METHOD__, 10); $this->CommitTransaction(); UserGenericStatusFactory::queueGenericStatus($generic_queue_status_label, 20, TTi18n::gettext('Pay Stub for this employee already exists, skipping...'), NULL); return FALSE; } if ($pay_stub->isValid() == TRUE) { $pay_stub->Save(FALSE); $pay_stub->setStatus(25); //Open } else { Debug::text('Pay Stub isValid failed!', __FILE__, __LINE__, __METHOD__, 10); UserGenericStatusFactory::queueGenericStatus($generic_queue_status_label, 10, $pay_stub->Validator->getTextErrors(), NULL); $this->FailTransaction(); $this->CommitTransaction(); return FALSE; } $pay_stub->loadPreviousPayStub(); $user_date_total_arr = $this->getWageObject()->getUserDateTotalArray(); if (isset($user_date_total_arr['entries']) and is_array($user_date_total_arr['entries'])) { foreach ($user_date_total_arr['entries'] as $udt_arr) { //Allow negative amounts so flat rate premium policies can reduce an employees wage if need be. if ($udt_arr['amount'] != 0) { Debug::text('Adding Pay Stub Entry: ' . $udt_arr['pay_stub_entry'] . ' Amount: ' . $udt_arr['amount'], __FILE__, __LINE__, __METHOD__, 10); $pay_stub->addEntry($udt_arr['pay_stub_entry'], $udt_arr['amount'], TTDate::getHours($udt_arr['total_time']), $udt_arr['rate']); } else { Debug::text('NOT Adding ($0 amount) Pay Stub Entry: ' . $udt_arr['pay_stub_entry'] . ' Amount: ' . $udt_arr['amount'], __FILE__, __LINE__, __METHOD__, 10); } } } else { //No Earnings, CHECK FOR PS AMENDMENTS next for earnings. Debug::text('NO TimeSheet EARNINGS ON PAY STUB... Checking for PS amendments', __FILE__, __LINE__, __METHOD__, 10); } //Get all PS amendments and Tax / Deductions so we can determine the proper order to calculate them in. $psalf = TTnew('PayStubAmendmentListFactory'); $psalf->getByUserIdAndAuthorizedAndStartDateAndEndDate($this->getUser(), TRUE, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate()); $udlf = TTnew('UserDeductionListFactory'); $udlf->getByCompanyIdAndUserId($this->getUserObject()->getCompany(), $this->getUserObject()->getId()); if (getTTProductEdition() >= TT_PRODUCT_ENTERPRISE and $this->getUserObject()->getCompanyObject()->getProductEdition() >= TT_PRODUCT_ENTERPRISE) { $uelf = TTnew('UserExpenseListFactory'); $uelf->getByUserIdAndAuthorizedAndStartDateAndEndDate($this->getUser(), TRUE, $this->getPayPeriodObject()->getStartDate(), $this->getPayPeriodObject()->getEndDate()); Debug::text('Total User Expenses: ' . $uelf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); } else { $uelf = FALSE; } $deduction_order_arr = $this->getOrderedDeductionAndPSAmendment($udlf, $psalf, $uelf); if (is_array($deduction_order_arr) and count($deduction_order_arr) > 0) { foreach ($deduction_order_arr as $calculation_order => $data_arr) { Debug::text('Found PS Amendment/Deduction: Type: ' . $data_arr['type'] . ' Name: ' . $data_arr['name'] . ' Order: ' . $calculation_order, __FILE__, __LINE__, __METHOD__, 10); if (isset($data_arr['obj']) and is_object($data_arr['obj'])) { if ($data_arr['type'] == 'UserDeductionListFactory') { $ud_obj = $data_arr['obj']; //Determine if this deduction is valid based on start/end dates. //Determine if this deduction is valid based on min/max length of service. //Determine if this deduction is valid based on min/max user age. if ($ud_obj->getCompanyDeductionObject()->isActiveDate($pay_stub->getPayPeriodObject()->getEndDate()) == TRUE and $ud_obj->getCompanyDeductionObject()->isActiveLengthOfService($this->getUserObject(), $pay_stub->getPayPeriodObject()->getEndDate()) == TRUE and $ud_obj->getCompanyDeductionObject()->isActiveUserAge($this->getUserObject(), $pay_stub->getPayPeriodObject()->getEndDate()) == TRUE and $ud_obj->getCompanyDeductionObject()->inApplyFrequencyWindow($pay_stub->getPayPeriodObject()->getStartDate(), $pay_stub->getPayPeriodObject()->getEndDate(), $this->getUserObject()->getHireDate(), $this->getUserObject()->getTerminationDate(), $this->getUserObject()->getBirthDate()) == TRUE) { $amount = $ud_obj->getDeductionAmount($this->getUserObject()->getId(), $pay_stub, $this->getPayPeriodObject()); Debug::text('User Deduction: ' . $ud_obj->getCompanyDeductionObject()->getName() . ' Amount: ' . $amount . ' Calculation Order: ' . $ud_obj->getCompanyDeductionObject()->getCalculationOrder(), __FILE__, __LINE__, __METHOD__, 10); //Allow negative amounts, so they can reduce previously calculated deductions or something. if (isset($amount) and $amount != 0) { $pay_stub->addEntry($ud_obj->getCompanyDeductionObject()->getPayStubEntryAccount(), $amount, NULL, NULL, $ud_obj->getCompanyDeductionObject()->getPayStubEntryDescription()); } else { Debug::text('Amount is 0, skipping...', __FILE__, __LINE__, __METHOD__, 10); } } unset($amount, $ud_obj); } elseif ($data_arr['type'] == 'PayStubAmendmentListFactory') { $psa_obj = $data_arr['obj']; Debug::text('Found Pay Stub Amendment: ID: ' . $psa_obj->getID() . ' Entry Name ID: ' . $psa_obj->getPayStubEntryNameId() . ' Type: ' . $psa_obj->getType(), __FILE__, __LINE__, __METHOD__, 10); $amount = $psa_obj->getCalculatedAmount($pay_stub); if (isset($amount) and $amount != 0) { Debug::text('Pay Stub Amendment Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10); //Keep in mind this causes pay stubs to be re-generated every time, as this modifies the updated time //to slightly more then the pay stub creation time. $psa_obj->setStatus(52); //InUse if ($psa_obj->isValid()) { $pay_stub->addEntry($psa_obj->getPayStubEntryNameId(), $amount, $psa_obj->getUnits(), $psa_obj->getRate(), $psa_obj->getDescription(), $psa_obj->getID(), NULL, NULL, $psa_obj->getYTDAdjustment()); $psa_obj->Save(); } } else { Debug::text('bPay Stub Amendment Amount is not set...', __FILE__, __LINE__, __METHOD__, 10); } unset($amount, $psa_obj); } elseif ($data_arr['type'] == 'UserExpenseListFactory') { $ue_obj = $data_arr['obj']; Debug::text('Found User Expense: ID: ' . $ue_obj->getID() . ' Expense Policy ID: ' . $ue_obj->getExpensePolicy(), __FILE__, __LINE__, __METHOD__, 10); $amount = $ue_obj->getReimburseAmount(); if (isset($amount) and $amount != 0) { Debug::text('User Expense reimbursable Amount: ' . $amount, __FILE__, __LINE__, __METHOD__, 10); $pay_stub->addEntry($ue_obj->getExpensePolicyObject()->getPayStubEntryAccount(), $amount, NULL, NULL, NULL, NULL, NULL, NULL, FALSE, $ue_obj->getID()); //Keep in mind this causes pay stubs to be re-generated every time, as this modifies the updated time //to slightly more then the pay stub creation time. $ue_obj->setStatus(35); //InUse $ue_obj->Save(); } else { Debug::text('bUser Expense Amount is not set...', __FILE__, __LINE__, __METHOD__, 10); } unset($amount, $ue_obj); } } } } unset($deduction_order_arr, $calculation_order, $data_arr); $pay_stub_id = $pay_stub->getId(); $pay_stub->setEnableProcessEntries(TRUE); $pay_stub->processEntries(); if ($pay_stub->isValid() == TRUE) { Debug::text('Pay Stub is valid, final save.', __FILE__, __LINE__, __METHOD__, 10); $pay_stub->setEnableCalcYTD(TRUE); //When recalculating old pay stubs in the middle of the year, we need to make sure YTD values are updated. $pay_stub->Save(); if ($this->getEnableCorrection() == TRUE) { if (isset($old_pay_stub_id)) { Debug::text('bCorrection Enabled - Doing Comparison here', __FILE__, __LINE__, __METHOD__, 10); PayStubFactory::CalcDifferences($pay_stub_id, $old_pay_stub_id); } //Delete newly created temp paystub. //This used to be in the above IF block that depended on $old_pay_stub_id //being set, however in cases where the old pay stub didn't exist //TimeTrex wouldn't delete these temporary pay stubs. //Moving this code outside that IF statement so it only depends on EnableCorrection() //to be TRUE should fix that issue. $pslf = TTnew('PayStubListFactory'); $pslf->getById($pay_stub_id); if ($pslf->getRecordCount() > 0) { $tmp_ps_obj = $pslf->getCurrent(); $tmp_ps_obj->setDeleted(TRUE); $tmp_ps_obj->Save(); unset($tmp_ps_obj); } } $pay_stub->CommitTransaction(); UserGenericStatusFactory::queueGenericStatus($generic_queue_status_label, 30, NULL, NULL); return TRUE; } Debug::text('Pay Stub is NOT valid returning FALSE', __FILE__, __LINE__, __METHOD__, 10); UserGenericStatusFactory::queueGenericStatus($generic_queue_status_label, 10, $pay_stub->Validator->getTextErrors(), NULL); $pay_stub->FailTransaction(); //Reduce transaction count by one. $pay_stub->CommitTransaction(); return FALSE; }
function testRoundingD() { global $dd; $this->createPayPeriodSchedule(10); $this->createPayPeriods(); $this->getAllPayPeriods(); $policy_ids['round'][] = $dd->createRoundingPolicy($this->company_id, 30); //Day Total $policy_ids['round'][] = $dd->createRoundingPolicy($this->company_id, 40); //Lunch Total $policy_ids['round'][] = $dd->createRoundingPolicy($this->company_id, 50); //Break Total //Create Policy Group $dd->createPolicyGroup($this->company_id, NULL, NULL, NULL, NULL, NULL, $policy_ids['round'], array($this->user_id)); $date_epoch = TTDate::getBeginWeekEpoch(time()); $date_stamp = TTDate::getDate('DATE', $date_epoch); $dd->createPunchPair($this->user_id, strtotime($date_stamp . ' 8:03AM'), NULL, array('in_type_id' => 10, 'out_type_id' => 20, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $dd->createPunchPair($this->user_id, NULL, strtotime($date_stamp . ' 12:06PM'), array('in_type_id' => 10, 'out_type_id' => 30, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $dd->createPunchPair($this->user_id, strtotime($date_stamp . ' 1:12PM'), NULL, array('in_type_id' => 30, 'out_type_id' => 10, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $dd->createPunchPair($this->user_id, NULL, strtotime($date_stamp . ' 5:07PM'), array('in_type_id' => 20, 'out_type_id' => 10, 'branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_arr = $this->getPunchDataArray(TTDate::getBeginDayEpoch($date_epoch), TTDate::getEndDayEpoch($date_epoch)); //print_r($punch_arr); $this->assertEquals(2, count($punch_arr[$date_epoch])); $this->assertEquals($punch_arr[$date_epoch][0]['shift_data']['punches'][0]['time_stamp'], strtotime($date_stamp . ' 8:03AM')); $this->assertEquals($punch_arr[$date_epoch][0]['shift_data']['punches'][1]['time_stamp'], strtotime($date_stamp . ' 12:06PM')); $this->assertEquals($punch_arr[$date_epoch][0]['shift_data']['punches'][2]['time_stamp'], strtotime($date_stamp . ' 1:06PM')); $this->assertEquals($punch_arr[$date_epoch][0]['shift_data']['punches'][3]['time_stamp'], strtotime($date_stamp . ' 5:03PM')); $udt_arr = $this->getUserDateTotalArray($date_epoch, $date_epoch); //Total Time $this->assertEquals(10, $udt_arr[$date_epoch][0]['status_id']); $this->assertEquals(10, $udt_arr[$date_epoch][0]['type_id']); $this->assertEquals(8 * 3600, $udt_arr[$date_epoch][0]['total_time']); return TRUE; }
function getHolidayUserDateIDs() { Debug::text('reCalculating Holiday...', __FILE__, __LINE__, __METHOD__, 10); //Get Holiday policies and determine how many days we need to look ahead/behind in order //to recalculate the holiday eligilibility/time. $holiday_before_days = 0; $holiday_after_days = 0; $hplf = new HolidayPolicyListFactory(); $hplf->getByCompanyId($this->getUserDateObject()->getUserObject()->getCompany()); if ($hplf->getRecordCount() > 0) { foreach ($hplf as $hp_obj) { if ($hp_obj->getMinimumWorkedPeriodDays() > $holiday_before_days) { $holiday_before_days = $hp_obj->getMinimumWorkedPeriodDays(); } if ($hp_obj->getAverageTimeDays() > $holiday_before_days) { $holiday_before_days = $hp_obj->getAverageTimeDays(); } if ($hp_obj->getMinimumWorkedAfterPeriodDays() > $holiday_after_days) { $holiday_after_days = $hp_obj->getMinimumWorkedAfterPeriodDays(); } } } Debug::text('Holiday Before Days: ' . $holiday_before_days . ' Holiday After Days: ' . $holiday_after_days, __FILE__, __LINE__, __METHOD__, 10); if ($holiday_before_days > 0 or $holiday_after_days > 0) { $retarr = array(); $search_start_date = TTDate::getBeginWeekEpoch($this->getUserDateObject()->getDateStamp() - $holiday_after_days * 86400); $search_end_date = TTDate::getEndWeekEpoch(TTDate::getEndDayEpoch($this->getUserDateObject()->getDateStamp()) + $holiday_before_days * 86400 + 3601); Debug::text('Holiday search start date: ' . TTDate::getDate('DATE', $search_start_date) . ' End date: ' . TTDate::getDate('DATE', $search_end_date) . ' Current Date: ' . TTDate::getDate('DATE', $this->getUserDateObject()->getDateStamp()), __FILE__, __LINE__, __METHOD__, 10); $hlf = new HolidayListFactory(); //$hlf->getByPolicyGroupUserIdAndStartDateAndEndDate( $this->getUserDateObject()->getUser(), TTDate::getEndWeekEpoch( $this->getUserDateObject()->getDateStamp() )+86400, TTDate::getEndDayEpoch()+($max_average_time_days*86400)+3601 ); $hlf->getByPolicyGroupUserIdAndStartDateAndEndDate($this->getUserDateObject()->getUser(), $search_start_date, $search_end_date); if ($hlf->getRecordCount() > 0) { Debug::text('Found Holidays within range: ' . $hlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); $udlf = new UserDateListFactory(); foreach ($hlf as $h_obj) { Debug::text('ReCalculating Day due to Holiday: ' . TTDate::getDate('DATE', $h_obj->getDateStamp()), __FILE__, __LINE__, __METHOD__, 10); $user_date_ids = $udlf->getArrayByListFactory($udlf->getByUserIdAndDate($this->getUserDateObject()->getUser(), $h_obj->getDateStamp())); if (is_array($user_date_ids)) { $retarr = array_merge($retarr, $user_date_ids); } unset($user_date_ids); } } } if (isset($retarr) and is_array($retarr) and count($retarr) > 0) { //Debug::Arr($retarr, 'Holiday UserDateIDs: ', __FILE__, __LINE__, __METHOD__, 10); return $retarr; } Debug::text('No Holidays within range...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; }
function getScheduleArray($filter_data) { global $current_user, $current_user_prefs; //Get all schedule data by general filter criteria. Debug::Arr($filter_data, 'Filter Data: ', __FILE__, __LINE__, __METHOD__, 10); if (!isset($filter_data['start_date']) or $filter_data['start_date'] == '') { return FALSE; } if (!isset($filter_data['end_date']) or $filter_data['end_date'] == '') { return FALSE; } $filter_data['start_date'] = TTDate::getBeginDayEpoch($filter_data['start_date']); $filter_data['end_date'] = TTDate::getEndDayEpoch($filter_data['end_date']); $blf = new BranchListFactory(); $branch_options = $blf->getByCompanyIdArray($current_user->getCompany(), FALSE); $dlf = new DepartmentListFactory(); $department_options = $dlf->getByCompanyIdArray($current_user->getCompany(), FALSE); $slf = new ScheduleListFactory(); $slf->getSearchByCompanyIdAndArrayCriteria($current_user->getCompany(), $filter_data); Debug::text('Found Scheduled Rows: ' . $slf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); if ($slf->getRecordCount() > 0) { foreach ($slf as $s_obj) { Debug::text('Schedule ID: ' . $s_obj->getId() . ' User ID: ' . $s_obj->getColumn('user_id') . ' Start Time: ' . $s_obj->getStartTime(), __FILE__, __LINE__, __METHOD__, 10); if (is_object($s_obj->getAbsencePolicyObject())) { $absence_policy_name = (string) $s_obj->getAbsencePolicyObject()->getName(); } else { $absence_policy_name = 'N/A'; } $iso_date_stamp = TTDate::getISODateStamp($s_obj->getStartTime()); $schedule_shifts[$iso_date_stamp][$s_obj->getColumn('user_id') . $s_obj->getStartTime()] = array('id' => (int) $s_obj->getID(), 'user_id' => (int) $s_obj->getColumn('user_id'), 'user_created_by' => (int) $s_obj->getColumn('user_created_by'), 'user_full_name' => Misc::getFullName($s_obj->getColumn('first_name'), NULL, $s_obj->getColumn('last_name'), FALSE, FALSE), 'first_name' => $s_obj->getColumn('first_name'), 'last_name' => $s_obj->getColumn('last_name'), 'status_id' => (int) $s_obj->getStatus(), 'date_stamp' => TTDate::getAPIDate('DATE', TTDate::parseDateTime($s_obj->getColumn('date_stamp'))), 'start_date' => defined('TIMETREX_API') ? TTDate::getAPIDate('DATE+TIME', $s_obj->getStartTime()) : $s_obj->getStartTime(), 'end_date' => defined('TIMETREX_API') ? TTDate::getAPIDate('DATE+TIME', $s_obj->getEndTime()) : $s_obj->getEndTime(), 'start_time' => defined('TIMETREX_API') ? TTDate::getAPIDate('TIME', $s_obj->getStartTime()) : $s_obj->getStartTime(), 'end_time' => defined('TIMETREX_API') ? TTDate::getAPIDate('TIME', $s_obj->getEndTime()) : $s_obj->getEndTime(), 'total_time' => $s_obj->getTotalTime(), 'schedule_policy_id' => (int) $s_obj->getSchedulePolicyID(), 'absence_policy_id' => (int) $s_obj->getAbsencePolicyID(), 'absence_policy' => $absence_policy_name, 'branch_id' => (int) $s_obj->getBranch(), 'branch' => Option::getByKey($s_obj->getBranch(), $branch_options, NULL), 'department_id' => (int) $s_obj->getDepartment(), 'department' => Option::getByKey($s_obj->getDepartment(), $department_options, NULL)); $schedule_shifts_index[$iso_date_stamp][$s_obj->getColumn('user_id')][] = $s_obj->getColumn('user_id') . $s_obj->getStartTime(); unset($absence_policy_name); } //Debug::Arr($schedule_shifts, 'Committed Schedule Shifts: ', __FILE__, __LINE__, __METHOD__, 10); //Debug::Arr($schedule_shifts_index, 'Committed Schedule Shifts Index: ', __FILE__, __LINE__, __METHOD__, 10); } else { $schedule_shifts = array(); } unset($slf); //Get holidays //FIXME: What if there are two holiday policies, one that defaults to working, and another that defaults to not working, and they are assigned //to two different groups of employees? For that matter what if the holiday policy isn't assigned to a specific user at all. $holiday_data = array(); $hlf = new HolidayListFactory(); $hlf->getByCompanyIdAndStartDateAndEndDate($current_user->getCompany(), $filter_data['start_date'], $filter_data['end_date']); Debug::text('Found Holiday Rows: ' . $hlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); foreach ($hlf as $h_obj) { if (is_object($h_obj->getHolidayPolicyObject()) and is_object($h_obj->getHolidayPolicyObject()->getAbsencePolicyObject())) { $holiday_data[TTDate::getISODateStamp($h_obj->getDateStamp())] = array('status_id' => (int) $h_obj->getHolidayPolicyObject()->getDefaultScheduleStatus(), 'absence_policy_id' => $h_obj->getHolidayPolicyObject()->getAbsencePolicyID(), 'absence_policy' => $h_obj->getHolidayPolicyObject()->getAbsencePolicyObject()->getName()); } else { $holiday_data[TTDate::getISODateStamp($h_obj->getDateStamp())] = array('status_id' => 10); //Working } } unset($hlf); $recurring_schedule_shifts = array(); $recurring_schedule_shifts_index = array(); $rstlf = new RecurringScheduleTemplateListFactory(); $rstlf->getSearchByCompanyIdAndArrayCriteria($current_user->getCompany(), $filter_data); Debug::text('Found Recurring Schedule Template Rows: ' . $rstlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); if ($rstlf->getRecordCount() > 0) { foreach ($rstlf as $rst_obj) { //Debug::text('Recurring Schedule Template ID: '. $rst_obj->getID() , __FILE__, __LINE__, __METHOD__, 10); $rst_obj->getShifts($filter_data['start_date'], $filter_data['end_date'], $holiday_data, $branch_options, $department_options, &$schedule_shifts, &$schedule_shifts_index); } } else { Debug::text('DID NOT find Recurring Schedule for this time period: ', __FILE__, __LINE__, __METHOD__, 10); } //Debug::Arr($schedule_shifts, 'Schedule Shifts: ', __FILE__, __LINE__, __METHOD__, 10); unset($schedule_shifts_index, $recurring_schedule_shifts_index); if (isset($schedule_shifts)) { return $schedule_shifts; } return FALSE; }
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; }
function calcExperience() { if ($this->getFirstUsedDate() != '') { $last_used_date = $this->getLastUsedDate(); if ($this->getLastUsedDate() == '') { $last_used_date = TTDate::getEndDayEpoch(time()); } $total_time = round(TTDate::getYears($last_used_date - TTDate::getBeginDayEpoch($this->getFirstUsedDate())), 2); if ($total_time < 0) { $total_time = 0; } Debug::text(' First Used Date: ' . $this->getFirstUsedDate() . ' Last Used Date: ' . $last_used_date . ' Total Yrs: ' . $total_time, __FILE__, __LINE__, __METHOD__, 10); return $total_time; } return FALSE; }
public static function getTimePeriodDates($time_period, $epoch = NULL, $user_obj = NULL, $params = NULL) { $time_period = Misc::trimSortPrefix($time_period); if ($epoch == NULL or $epoch == '' or !is_numeric($epoch)) { $epoch = self::getTime(); } $start_week_day = 0; if (is_object($user_obj)) { $user_prefs = $user_obj->getUserPreferenceObject(); if (is_object($user_prefs)) { $start_week_day = $user_prefs->getStartWeekDay(); } } switch ($time_period) { case 'custom_date': //Params must pass start_date/end_date if (isset($params['start_date'])) { $start_date = TTDate::getBeginDayEpoch($params['start_date']); } if (isset($params['end_date'])) { $end_date = TTDate::getEndDayEpoch($params['end_date']); } break; case 'custom_time': //Params must pass start_date/end_date if (isset($params['start_date'])) { $start_date = $params['start_date']; } if (isset($params['end_date'])) { $end_date = $params['end_date']; } break; case 'custom_pay_period': //Params must pass pay_period_ids if (isset($params['pay_period_id'])) { $pay_period_ids = (array) $params['pay_period_id']; } break; case 'today': $start_date = TTDate::getBeginDayEpoch($epoch); $end_date = TTDate::getEndDayEpoch($epoch); break; case 'yesterday': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'last_24_hours': $start_date = $epoch - 86400; $end_date = $epoch; break; case 'last_48_hours': $start_date = $epoch - 86400 * 2; $end_date = $epoch; break; case 'last_72_hours': $start_date = $epoch - 86400 * 3; $end_date = $epoch; break; case 'this_week': $start_date = TTDate::getBeginWeekEpoch($epoch, $start_week_day); $end_date = TTDate::getEndWeekEpoch($epoch, $start_week_day); break; case 'last_week': $start_date = TTDate::getBeginWeekEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7, $start_week_day); $end_date = TTDate::getEndWeekEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7, $start_week_day); break; case 'last_2_weeks': $start_date = TTDate::getBeginWeekEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 14, $start_week_day); $end_date = TTDate::getEndWeekEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7, $start_week_day); break; case 'last_7_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'last_14_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 14); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; //Params must be passed if more than one pay period schedule exists. //Params must be passed if more than one pay period schedule exists. case 'no_pay_period': case 'this_pay_period': case 'last_pay_period': Debug::text('Time Period for Pay Period Schedule selected...', __FILE__, __LINE__, __METHOD__, 10); //Make sure user_obj is set. if (!is_object($user_obj)) { Debug::text('User Object was not passsed...', __FILE__, __LINE__, __METHOD__, 10); break; } if (!isset($params['pay_period_schedule_id'])) { $params['pay_period_schedule_id'] = NULL; } $pay_period_ids = array(); //Since we allow multiple pay_period schedules to be selected, we have to return pay_period_ids, not start/end dates. if ($time_period == 'this_pay_period') { Debug::text('this_pay_period', __FILE__, __LINE__, __METHOD__, 10); $pplf = TTnew('PayPeriodListFactory'); $pplf->getThisPayPeriodByCompanyIdAndPayPeriodScheduleIdAndDate($user_obj->getCompany(), $params['pay_period_schedule_id'], time()); if ($pplf->getRecordCount() > 0) { foreach ($pplf as $pp_obj) { $pay_period_ids[] = $pp_obj->getId(); } } } elseif ($time_period == 'last_pay_period') { Debug::text('last_pay_period', __FILE__, __LINE__, __METHOD__, 10); $pplf = TTnew('PayPeriodListFactory'); $pplf->getLastPayPeriodByCompanyIdAndPayPeriodScheduleIdAndDate($user_obj->getCompany(), $params['pay_period_schedule_id'], time()); if ($pplf->getRecordCount() > 0) { foreach ($pplf as $pp_obj) { $pay_period_ids[] = $pp_obj->getId(); } } } else { Debug::text('no_pay_period', __FILE__, __LINE__, __METHOD__, 10); } Debug::Arr($pay_period_ids, 'Pay Period IDs: ', __FILE__, __LINE__, __METHOD__, 10); if (count($pay_period_ids) == 0) { unset($pay_period_ids); } break; case 'this_month': $start_date = TTDate::getBeginMonthEpoch($epoch); $end_date = TTDate::getEndMonthEpoch($epoch); break; case 'last_month': $start_date = TTDate::getBeginMonthEpoch(TTDate::getBeginMonthEpoch($epoch) - 86400); $end_date = TTDate::getEndMonthEpoch(TTDate::getBeginMonthEpoch($epoch) - 86400); break; case 'last_2_months': $start_date = TTDate::getBeginMonthEpoch(TTDate::getBeginMonthEpoch($epoch) - 86400 * 32); $end_date = TTDate::getEndMonthEpoch(TTDate::getBeginMonthEpoch($epoch) - 86400); break; case 'last_30_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 30); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'last_45_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 45); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'last_60_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 60); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'this_quarter': $quarter = TTDate::getYearQuarter($epoch); $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); //Debug::Arr($quarter_dates, 'Quarter Dates: Quarter: '. $quarter, __FILE__, __LINE__, __METHOD__,10); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_quarter': $quarter = TTDate::getYearQuarter($epoch) - 1; if ($quarter == 0) { $quarter = 4; $epoch = TTDate::getBeginYearEpoch() - 86400; //Need to jump back into the previous year. } $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_90_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 90); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); break; case 'this_year_1st_quarter': $quarter = 1; $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'this_year_2nd_quarter': $quarter = 2; $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'this_year_3rd_quarter': $quarter = 3; $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'this_year_4th_quarter': $quarter = 4; $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_year_1st_quarter': $quarter = 1; $quarter_dates = TTDate::getYearQuarters(TTDate::getBeginYearEpoch($epoch) - 86400, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_year_2nd_quarter': $quarter = 2; $quarter_dates = TTDate::getYearQuarters(TTDate::getBeginYearEpoch($epoch) - 86400, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_year_3rd_quarter': $quarter = 3; $quarter_dates = TTDate::getYearQuarters(TTDate::getBeginYearEpoch($epoch) - 86400, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_year_4th_quarter': $quarter = 4; $quarter_dates = TTDate::getYearQuarters(TTDate::getBeginYearEpoch($epoch) - 86400, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'last_3_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date) - 3, TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date)); break; case 'last_6_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date) - 6, TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date)); break; case 'last_9_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date) - 9, TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date)); break; case 'last_12_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date), TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date) - 1); break; case 'last_18_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date) - 18, TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date)); break; case 'last_24_months': $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date) - 24, TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date)); break; case 'this_year': $start_date = TTDate::getBeginYearEpoch($epoch); $end_date = TTDate::getEndYearEpoch($epoch); break; case 'last_year': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400); $end_date = TTDate::getEndYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400); break; case 'last_2_years': $end_date = TTDate::getEndYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date), TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date) - 2); break; case 'last_3_years': $end_date = TTDate::getEndYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date), TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date) - 3); break; case 'last_5_years': $end_date = TTDate::getEndYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400); $start_date = mktime(0, 0, 0, TTDate::getMonth($end_date), TTDate::getDayOfMonth($end_date), TTDate::getYear($end_date) - 5); break; case 'to_yesterday': //"Up To" means we need to use the end time of the day we go up to. $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400) - 1; break; case 'to_today': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch)) - 1; break; case 'to_this_week': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginWeekEpoch($epoch, $start_week_day) - 1; break; case 'to_last_week': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginWeekEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7, $start_week_day) - 1; break; case 'to_7_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 7) - 1; break; case 'to_14_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 14) - 1; break; case 'to_last_pay_period': case 'to_this_pay_period': Debug::text('Time Period for Pay Period Schedule selected...', __FILE__, __LINE__, __METHOD__, 10); //Make sure user_obj is set. if (!is_object($user_obj)) { Debug::text('User Object was not passsed...', __FILE__, __LINE__, __METHOD__, 10); break; } if (!isset($params['pay_period_schedule_id'])) { $params['pay_period_schedule_id'] = NULL; } $end_date = FALSE; //Since we allow multiple pay_period schedules to be selected, we have to return pay_period_ids, not start/end dates. if ($time_period == 'to_this_pay_period') { Debug::text('to_this_pay_period', __FILE__, __LINE__, __METHOD__, 10); $pplf = TTnew('PayPeriodListFactory'); $pplf->getThisPayPeriodByCompanyIdAndPayPeriodScheduleIdAndDate($user_obj->getCompany(), $params['pay_period_schedule_id'], time()); if ($pplf->getRecordCount() > 0) { foreach ($pplf as $pp_obj) { if ($end_date == FALSE or $pp_obj->getStartDate() < $end_date) { $end_date = $pp_obj->getStartDate(); } } } } elseif ($time_period == 'to_last_pay_period') { Debug::text('to_last_pay_period', __FILE__, __LINE__, __METHOD__, 10); $pplf = TTnew('PayPeriodListFactory'); $pplf->getLastPayPeriodByCompanyIdAndPayPeriodScheduleIdAndDate($user_obj->getCompany(), $params['pay_period_schedule_id'], time()); if ($pplf->getRecordCount() > 0) { foreach ($pplf as $pp_obj) { if ($end_date == FALSE or $pp_obj->getStartDate() < $end_date) { $end_date = $pp_obj->getStartDate(); } } } } $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = $end_date - 1; break; case 'to_last_month': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginMonthEpoch(TTDate::getBeginMonthEpoch($epoch) - 86400) - 1; break; case 'to_this_month': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginMonthEpoch($epoch) - 1; break; case 'to_30_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 30) - 1; break; case 'to_45_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 45) - 1; break; case 'to_60_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 60) - 1; break; case 'to_last_quarter': $quarter = TTDate::getYearQuarter($epoch) - 1; if ($quarter == 0) { $quarter = 4; $epoch = TTDate::getBeginYearEpoch() - 86400; //Need to jump back into the previous year. } $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = $quarter_dates['start'] - 1; break; case 'to_this_quarter': $quarter = TTDate::getYearQuarter($epoch); $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = $quarter_dates['start'] - 1; break; case 'to_90_days': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) - 86400 * 90) - 1; break; case 'to_this_year': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginYearEpoch($epoch) - 1; break; case 'to_last_year': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch($epoch) - 86400) - 1; break; case 'tomorrow': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); break; case 'next_24_hours': $start_date = $epoch; $end_date = $epoch + 86400; break; case 'next_48_hours': $start_date = $epoch; $end_date = $epoch + 86400 * 2; break; case 'next_72_hours': $start_date = $epoch; $end_date = $epoch + 86400 * 3; break; case 'next_week': $start_date = TTDate::getBeginWeekEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 7, $start_week_day); $end_date = TTDate::getEndWeekEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 7, $start_week_day); break; case 'next_2_weeks': $start_date = TTDate::getBeginWeekEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 7, $start_week_day); $end_date = TTDate::getEndWeekEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 14, $start_week_day); break; case 'next_7_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 7); break; case 'next_14_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 14); break; case 'next_month': $start_date = TTDate::getBeginMonthEpoch(TTDate::getEndMonthEpoch($epoch) + 86400); $end_date = TTDate::getEndMonthEpoch(TTDate::getEndMonthEpoch($epoch) + 86400); break; case 'next_2_months': $start_date = TTDate::getBeginMonthEpoch(TTDate::getEndMonthEpoch($epoch) + 86400); $end_date = TTDate::getEndMonthEpoch(TTDate::getEndMonthEpoch($epoch) + 86400 * 32); break; case 'next_30_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 30); break; case 'next_45_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 45); break; case 'next_60_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 60); break; case 'next_quarter': $quarter = TTDate::getYearQuarter($epoch) + 1; if ($quarter == 5) { $quarter = 1; $epoch = TTDate::getEndYearEpoch() + 86400; //Need to jump back into the previous year. } $quarter_dates = TTDate::getYearQuarters($epoch, $quarter); $start_date = $quarter_dates['start']; $end_date = $quarter_dates['end']; break; case 'next_90_days': $start_date = TTDate::getBeginDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400 * 90); break; case 'next_3_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 3, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_6_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 6, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_9_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 9, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_12_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 12, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_18_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 18, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_24_months': $start_date = TTDate::getEndDayEpoch(TTDate::getMiddleDayEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date) + 24, TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date)); break; case 'next_year': $start_date = TTDate::getBeginYearEpoch(TTDate::getEndYearEpoch($epoch) + 86400); $end_date = TTDate::getEndYearEpoch(TTDate::getEndYearEpoch($epoch) + 86400); break; case 'next_2_years': $start_date = TTDate::getEndYearEpoch(TTDate::getEndYearEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date), TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date) + 2); break; case 'next_3_years': $start_date = TTDate::getEndYearEpoch(TTDate::getEndYearEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date), TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date) + 3); break; case 'next_5_years': $start_date = TTDate::getEndYearEpoch(TTDate::getEndYearEpoch($epoch) + 86400); $end_date = mktime(0, 0, 0, TTDate::getMonth($start_date), TTDate::getDayOfMonth($start_date), TTDate::getYear($start_date) + 5); break; case 'all_years': $start_date = TTDate::getBeginYearEpoch(TTDate::getBeginYearEpoch(31564800) - 86400); $end_date = TTDate::getEndYearEpoch(time() + 86400 * (365 * 2)); break; default: break; } if (isset($start_date) and isset($end_date)) { //Debug::text('Period: '. $time_period .' Start: '. TTDate::getDate('DATE+TIME', $start_date ) .'('.$start_date.') End: '. TTDate::getDate('DATE+TIME', $end_date ) .'('.$end_date.')', __FILE__, __LINE__, __METHOD__,10); return array('start_date' => $start_date, 'end_date' => $end_date); } elseif (isset($pay_period_ids)) { //Debug::text('Period: '. $time_period .' returning just pay_period_ids...', __FILE__, __LINE__, __METHOD__,10); return array('pay_period_id' => $pay_period_ids); } return FALSE; }
function testBreakPunchTimeWindowD() { global $dd; $policy_ids['break'][] = $this->createBreakPolicy($this->company_id, 110); //Create Policy Group $dd->createPolicyGroup($this->company_id, NULL, NULL, NULL, NULL, NULL, NULL, array($this->user_id), $policy_ids['break']); $date_epoch = TTDate::getBeginWeekEpoch(time()); $date_stamp = TTDate::getDate('DATE', $date_epoch); $dd->createPunch($this->user_id, 10, 10, strtotime($date_stamp . ' 8:00AM'), array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_time = strtotime($date_stamp . ' 10:00AM'); $prev_punch_obj = $this->getPreviousPunch($punch_time); $punch_type_id = $prev_punch_obj->getNextType($punch_time); $punch_status_id = $prev_punch_obj->getNextStatus(); $this->assertEquals($punch_type_id, 10); //Normal - Because when using punch time it can't be detected on the first out punch. $this->assertEquals($punch_status_id, 20); //Out $dd->createPunch($this->user_id, $punch_type_id, $punch_status_id, $punch_time, array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_time = strtotime($date_stamp . ' 10:15AM'); $prev_punch_obj = $this->getPreviousPunch($punch_time); $punch_type_id = $prev_punch_obj->getNextType($punch_time); $punch_status_id = $prev_punch_obj->getNextStatus(); $this->assertEquals($punch_type_id, 30); //Break $this->assertEquals($punch_status_id, 10); //In $dd->createPunch($this->user_id, $punch_type_id, $punch_status_id, $punch_time, array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_time = strtotime($date_stamp . ' 2:00PM'); $prev_punch_obj = $this->getPreviousPunch($punch_time); $punch_type_id = $prev_punch_obj->getNextType($punch_time); $punch_status_id = $prev_punch_obj->getNextStatus(); $this->assertEquals($punch_type_id, 10); //Normal - Because when using punch time it can't be detected on the first out punch. $this->assertEquals($punch_status_id, 20); //Out $dd->createPunch($this->user_id, $punch_type_id, $punch_status_id, $punch_time, array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_time = strtotime($date_stamp . ' 2:15PM'); $prev_punch_obj = $this->getPreviousPunch($punch_time); $punch_type_id = $prev_punch_obj->getNextType($punch_time); $punch_status_id = $prev_punch_obj->getNextStatus(); $this->assertEquals($punch_type_id, 30); //Break $this->assertEquals($punch_status_id, 10); //In $dd->createPunch($this->user_id, $punch_type_id, $punch_status_id, $punch_time, array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_time = strtotime($date_stamp . ' 5:00PM'); $prev_punch_obj = $this->getPreviousPunch($punch_time); $punch_type_id = $prev_punch_obj->getNextType($punch_time); $punch_status_id = $prev_punch_obj->getNextStatus(); $this->assertEquals($punch_type_id, 10); //Normal $this->assertEquals($punch_status_id, 20); //Out $dd->createPunch($this->user_id, $punch_type_id, $punch_status_id, $punch_time, array('branch_id' => 0, 'department_id' => 0, 'job_id' => 0, 'job_item_id' => 0), TRUE); $punch_arr = $this->getPunchDataArray(TTDate::getBeginDayEpoch($date_epoch), TTDate::getEndDayEpoch($date_epoch)); //print_r($punch_arr); $this->assertEquals(3, count($punch_arr[$date_epoch])); $this->assertEquals($date_epoch, $punch_arr[$date_epoch][0]['date_stamp']); $this->assertEquals(6, count($punch_arr[$date_epoch][0]['shift_data']['punches'])); $this->assertEquals(10, $punch_arr[$date_epoch][0]['shift_data']['punches'][0]['type_id']); $this->assertEquals(10, $punch_arr[$date_epoch][0]['shift_data']['punches'][0]['status_id']); $this->assertEquals(30, $punch_arr[$date_epoch][0]['shift_data']['punches'][1]['type_id']); $this->assertEquals(20, $punch_arr[$date_epoch][0]['shift_data']['punches'][1]['status_id']); $this->assertEquals(30, $punch_arr[$date_epoch][0]['shift_data']['punches'][2]['type_id']); $this->assertEquals(10, $punch_arr[$date_epoch][0]['shift_data']['punches'][2]['status_id']); $this->assertEquals(30, $punch_arr[$date_epoch][0]['shift_data']['punches'][3]['type_id']); $this->assertEquals(20, $punch_arr[$date_epoch][0]['shift_data']['punches'][3]['status_id']); $this->assertEquals(30, $punch_arr[$date_epoch][0]['shift_data']['punches'][4]['type_id']); $this->assertEquals(10, $punch_arr[$date_epoch][0]['shift_data']['punches'][4]['status_id']); $this->assertEquals(10, $punch_arr[$date_epoch][0]['shift_data']['punches'][5]['type_id']); $this->assertEquals(20, $punch_arr[$date_epoch][0]['shift_data']['punches'][5]['status_id']); return TRUE; }
function getDateRangeSQL($str, $column, $format = 'epoch') { if ($str == '') { return FALSE; } if ($column == '') { return FALSE; } Debug::text(' Format: ' . $format . ' String: ' . $str . ' Column: ' . $column, __FILE__, __LINE__, __METHOD__, 10); $operators = array('>', '<', '>=', '<=', '='); $operations = FALSE; //Parse input, separate any subqueries first. $split_str = explode('&', $str, 2); //Limit sub-queries if (is_array($split_str)) { foreach ($split_str as $tmp_str) { $tmp_str = trim($tmp_str); $date = (int) TTDate::parseDateTime(str_replace($operators, '', $tmp_str)); //Debug::text(' Parsed Date: '. $tmp_str .' To: '. TTDate::getDate('DATE+TIME', $date) .' ('. $date .')', __FILE__, __LINE__, __METHOD__,10); if ($date != 0) { preg_match('/^>=|>|<=|</i', $tmp_str, $operator); //Debug::Arr($operator, ' Operator: ', __FILE__, __LINE__, __METHOD__,10); if (isset($operator[0]) and in_array($operator[0], $operators)) { if ($operator[0] == '<=') { $date = TTDate::getEndDayEpoch($date); } elseif ($operator[0] == '>') { $date = TTDate::getEndDayEpoch($date); } if ($format == 'timestamp') { $date = '\'' . $this->db->bindTimeStamp($date) . '\''; } elseif ($format == 'datestamp') { $date = '\'' . $this->db->bindDateStamp($date) . '\''; } $operations[] = $column . ' ' . $operator[0] . ' ' . $date; } else { $date1 = TTDate::getBeginDayEpoch($date); $date2 = TTDate::getEndDayEpoch($date); if ($format == 'timestamp') { $date1 = '\'' . $this->db->bindTimeStamp($date1) . '\''; $date2 = '\'' . $this->db->bindTimeStamp($date2) . '\''; } elseif ($format == 'datestamp') { $date1 = '\'' . $this->db->bindDateStamp($date1) . '\''; $date2 = '\'' . $this->db->bindDateStamp($date2) . '\''; } //Debug::text(' No operator specified... Using a 24hr period', __FILE__, __LINE__, __METHOD__,10); $operations[] = $column . ' >= ' . $date1; $operations[] = $column . ' <= ' . $date2; } } } } //Debug::Arr($operations, ' Operations: ', __FILE__, __LINE__, __METHOD__,10); if (is_array($operations)) { $retval = ' ( ' . implode(' AND ', $operations) . ' )'; Debug::text(' Query parts: ' . $retval, __FILE__, __LINE__, __METHOD__, 10); return $retval; } return FALSE; }
function getLookbackStartAndEndDates($pay_period_obj) { $retarr = array('start_date' => FALSE, 'end_date' => TTDate::getEndDayEpoch((int) $pay_period_obj->getTransactionDate() - 86400)); if ($this->getCompanyValue3() == 100) { //Pay Periods //Not implemented for now, as it has many issues, things like gaps between pay periods, employees switching between pay period schedules, etc... //We could just count the number of pay stubs, but this has issues with employees leaving and returning and such. } else { $length_of_service_days = bcmul((double) $this->getCompanyValue2(), $this->length_of_service_multiplier[(int) $this->getCompanyValue3()], 4); $retarr['start_date'] = TTDate::getBeginDayEpoch((int) $pay_period_obj->getTransactionDate() - $length_of_service_days * 86400); } Debug::text('Start Date: ' . TTDate::getDate('DATE+TIME', $retarr['start_date']) . ' End Date: ' . TTDate::getDate('DATE+TIME', $retarr['end_date']), __FILE__, __LINE__, __METHOD__, 10); return $retarr; }
function getHolidayUserDateIDs() { Debug::text('reCalculating Holiday...', __FILE__, __LINE__, __METHOD__, 10); //Get Holiday policies and determine how many days we need to look ahead/behind in order //to recalculate the holiday eligilibility/time. $holiday_before_days = 0; $holiday_after_days = 0; if (is_object($this->getUserDateObject()) and is_object($this->getUserDateObject()->getUserObject())) { $hplf = TTnew('HolidayPolicyListFactory'); $hplf->getByCompanyId($this->getUserDateObject()->getUserObject()->getCompany()); if ($hplf->getRecordCount() > 0) { foreach ($hplf as $hp_obj) { if ($hp_obj->getMinimumWorkedPeriodDays() > $holiday_before_days) { $holiday_before_days = $hp_obj->getMinimumWorkedPeriodDays(); } if ($hp_obj->getAverageTimeDays() > $holiday_before_days) { $holiday_before_days = $hp_obj->getAverageTimeDays(); } if ($hp_obj->getMinimumWorkedAfterPeriodDays() > $holiday_after_days) { $holiday_after_days = $hp_obj->getMinimumWorkedAfterPeriodDays(); } } } } Debug::text('Holiday Before Days: ' . $holiday_before_days . ' Holiday After Days: ' . $holiday_after_days, __FILE__, __LINE__, __METHOD__, 10); if ($holiday_before_days > 0 or $holiday_after_days > 0) { $retarr = array(); $search_start_date = TTDate::getBeginWeekEpoch($this->getUserDateObject()->getDateStamp() - $holiday_after_days * 86400); $search_end_date = TTDate::getEndWeekEpoch(TTDate::getEndDayEpoch($this->getUserDateObject()->getDateStamp()) + $holiday_before_days * 86400 + 3601); Debug::text('Holiday search start date: ' . TTDate::getDate('DATE', $search_start_date) . ' End date: ' . TTDate::getDate('DATE', $search_end_date) . ' Current Date: ' . TTDate::getDate('DATE', $this->getUserDateObject()->getDateStamp()), __FILE__, __LINE__, __METHOD__, 10); $hlf = TTnew('HolidayListFactory'); //$hlf->getByPolicyGroupUserIdAndStartDateAndEndDate( $this->getUserDateObject()->getUser(), TTDate::getEndWeekEpoch( $this->getUserDateObject()->getDateStamp() )+86400, TTDate::getEndDayEpoch()+($max_average_time_days*86400)+3601 ); $hlf->getByPolicyGroupUserIdAndStartDateAndEndDate($this->getUserDateObject()->getUser(), $search_start_date, $search_end_date); if ($hlf->getRecordCount() > 0) { Debug::text('Found Holidays within range: ' . $hlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); $udlf = TTnew('UserDateListFactory'); foreach ($hlf as $h_obj) { Debug::text('ReCalculating Day due to Holiday: ' . TTDate::getDate('DATE', $h_obj->getDateStamp()), __FILE__, __LINE__, __METHOD__, 10); $user_date_ids = $udlf->getArrayByListFactory($udlf->getByUserIdAndDate($this->getUserDateObject()->getUser(), $h_obj->getDateStamp())); if ($user_date_ids == FALSE and TTDate::getBeginDayEpoch($h_obj->getDateStamp()) <= TTDate::getBeginDayEpoch(time())) { //This fixes a bug where if an employee was added after a holiday (ie: Sept 3rd after Labor day of Sept 2nd) //then had time added before the holiday, the holiday would not be calculated as no user_date record would exist. $user_date_ids = (array) UserDateFactory::findOrInsertUserDate($this->getUserDateObject()->getUser(), TTDate::getBeginDayEpoch($h_obj->getDateStamp())); Debug::Text('User Date ID for holiday doesnt exist, creating it now: ' . $user_date_ids[0], __FILE__, __LINE__, __METHOD__, 10); } if (is_array($user_date_ids)) { $retarr = array_merge($retarr, $user_date_ids); } unset($user_date_ids); } } } if (isset($retarr) and is_array($retarr) and count($retarr) > 0) { //Debug::Arr($retarr, 'bHoliday UserDateIDs: ', __FILE__, __LINE__, __METHOD__, 10); return $retarr; } Debug::text('No Holidays within range...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; }
function getNextPayPeriod($end_date = NULL) { if (!$this->Validator->isValid()) { return FALSE; } //Manual Pay Period Schedule, skip repeating... if ($this->getType() == 5) { return FALSE; } $pplf = new PayPeriodListFactory(); //Debug::text('PP Schedule ID: '. $this->getId(), __FILE__, __LINE__, __METHOD__, 10); //Debug::text('PP Schedule Name: '. $this->getName(), __FILE__, __LINE__, __METHOD__, 10); Debug::text('PP Schedule Type (' . $this->getType() . '): ' . Option::getByKey($this->getType(), $this->getOptions('type')), __FILE__, __LINE__, __METHOD__, 10); //Debug::text('Anchor Date: '. $this->getAnchorDate() ." - ". TTDate::getDate('DATE+TIME', $this->getAnchorDate() ), __FILE__, __LINE__, __METHOD__, 10); //Debug::text('Primary Date: '. $this->getPrimaryDate() ." - ". TTDate::getDate('DATE+TIME', $this->getPrimaryDate() ), __FILE__, __LINE__, __METHOD__, 10); //Debug::text('Secondary Date: '. $this->getSecondaryDate() ." - ". TTDate::getDate('DATE+TIME', $this->getPrimaryDate() ), __FILE__, __LINE__, __METHOD__, 10); $last_pay_period_is_new = FALSE; if ($end_date != '' and $end_date != 0) { Debug::text('End Date is set: ' . TTDate::getDate('DATE+TIME', $end_date), __FILE__, __LINE__, __METHOD__, 10); $last_pay_period_end_date = $end_date; } else { Debug::text('Checking for Previous pay periods...', __FILE__, __LINE__, __METHOD__, 10); //Get the last pay period schedule in the database. $pplf->getByPayPeriodScheduleId($this->getId(), NULL, NULL, NULL, array('start_date' => 'desc')); $last_pay_period = $pplf->getCurrent(); if ($last_pay_period->isNew()) { $last_pay_period_is_new = TRUE; Debug::text('No Previous pay periods...', __FILE__, __LINE__, __METHOD__, 10); //Do this so a rollover doesn't happen while we're calculating. //$last_pay_period_end_date = TTDate::getTime(); //This causes the pay period schedule to jump ahead one month. So set this to be beginning of the month. $last_pay_period_end_date = TTDate::getBeginMonthEpoch(); } else { Debug::text('Previous pay periods found... ID: ' . $last_pay_period->getId(), __FILE__, __LINE__, __METHOD__, 10); $last_pay_period_end_date = $last_pay_period->getEndDate(); } unset($last_pay_period, $pplf); } Debug::text('aLast Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $last_pay_period_end_date) . ' (' . $last_pay_period_end_date . ')', __FILE__, __LINE__, __METHOD__, 10); //FIXME: This breaks having pay periods with different daily start times. //However, without it, I think DST breaks pay periods. //$last_pay_period_end_date = TTDate::getEndDayEpoch( $last_pay_period_end_date + 1 ) - 86400; $last_pay_period_end_date = TTDate::getEndDayEpoch($last_pay_period_end_date - 86400 / 2); Debug::text('bLast Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $last_pay_period_end_date) . ' (' . $last_pay_period_end_date . ')', __FILE__, __LINE__, __METHOD__, 10); if ($this->getDayStartTime() != 0) { Debug::text('Daily Start Time is set, adjusting Last Pay Period End Date by: ' . TTDate::getHours($this->getDayStartTime()), __FILE__, __LINE__, __METHOD__, 10); //Next adjust last_pay_period_end_date (which becomes the start date) to DayStartTime because then there could be a gap if they //change this mid-schedule. The End Date will take care of it after the first pay period. $last_pay_period_end_date = TTDate::getTimeLockedDate(TTDate::getBeginDayEpoch($last_pay_period_end_date) + $this->getDayStartTime(), $last_pay_period_end_date); Debug::text('cLast Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $last_pay_period_end_date) . ' (' . $last_pay_period_end_date . ')', __FILE__, __LINE__, __METHOD__, 10); } $insert_pay_period = 1; //deprecate primary pay periods. switch ($this->getType()) { case 10: //Weekly //Weekly case 20: //Bi-Weekly $last_pay_period_end_day_of_week = TTDate::getDayOfWeek($last_pay_period_end_date); Debug::text('Last Pay Period End Day Of Week: ' . $last_pay_period_end_day_of_week . ' Start Day Of Week: ' . $this->getStartDayOfWeek(), __LINE__, __METHOD__, 10); if ($last_pay_period_end_day_of_week != $this->getStartDayOfWeek()) { Debug::text('zTmp Pay Period End Date: ' . 'next ' . TTDate::getDayOfWeekByInt($this->getStartDayOfWeek()), __FILE__, __LINE__, __METHOD__, 10); //$tmp_pay_period_end_date = strtotime('next '. TTDate::getDayOfWeekByInt( $this->getStartDayOfWeek() ), $last_pay_period_end_date )-1; $tmp_pay_period_end_date = strtotime('next ' . TTDate::getDayOfWeekByInt($this->getStartDayOfWeek(), FALSE), $last_pay_period_end_date); //strtotime doesn't keep time when using "next", it resets it to midnight on the day, so we need to adjust for that. $tmp_pay_period_end_date = TTDate::getTimeLockedDate(TTDate::getBeginDayEpoch($tmp_pay_period_end_date) + $this->getDayStartTime(), $tmp_pay_period_end_date) - 1; } else { $tmp_pay_period_end_date = $last_pay_period_end_date; //This should fix a bug where if they are creating a new pay period schedule //starting on Monday with the anchor date of 01-Jul-08, it would start on 01-Jul-08 (Tue) //rather moving back to the Monday. if (TTDate::getDayOfMonth($tmp_pay_period_end_date) != TTDate::getDayOfMonth($tmp_pay_period_end_date + 1)) { Debug::text('Right on day boundary, minus an additional second to account for difference...', __FILE__, __LINE__, __METHOD__, 10); $tmp_pay_period_end_date--; } } Debug::text('aTmp Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $tmp_pay_period_end_date) . ' (' . $tmp_pay_period_end_date . ')', __FILE__, __LINE__, __METHOD__, 10); $start_date = $tmp_pay_period_end_date + 1; if ($this->getType() == 10) { //Weekly $tmp_pay_period_end_date = TTDate::getMiddleDayEpoch($start_date) + 86400 * 7; //Add one week } elseif ($this->getType() == 20) { //Bi-Weekly $tmp_pay_period_end_date = TTDate::getMiddleDayEpoch($start_date) + 86400 * 14; //Add two weeks } //Use Begin Day Epoch to nullify DST issues. $end_date = TTDate::getBeginDayEpoch($tmp_pay_period_end_date) - 1; $transaction_date = TTDate::getMiddleDayEpoch(TTDate::getMiddleDayEpoch($end_date) + $this->getTransactionDate() * 86400); break; case 30: //Semi-monthly $tmp_last_pay_period_end_day_of_month = TTDate::getDayOfMonth($last_pay_period_end_date + 1); Debug::text('bLast Pay Period End Day Of Month: ' . $tmp_last_pay_period_end_day_of_month, __FILE__, __LINE__, __METHOD__, 10); if ($tmp_last_pay_period_end_day_of_month == $this->convertLastDayOfMonth($this->getPrimaryDayOfMonth())) { $insert_pay_period = 1; $primary = TRUE; } elseif ($tmp_last_pay_period_end_day_of_month == $this->convertLastDayOfMonth($this->getSecondaryDayOfMonth())) { $insert_pay_period = 2; $primary = FALSE; } else { Debug::text('Finding if Primary or Secondary is closest...', __FILE__, __LINE__, __METHOD__, 10); $primary_date_offset = TTDate::getDateOfNextDayOfMonth($last_pay_period_end_date, NULL, $this->convertLastDayOfMonth($this->getPrimaryDayOfMonth())) - $last_pay_period_end_date; $secondary_date_offset = TTDate::getDateOfNextDayOfMonth($last_pay_period_end_date, NULL, $this->convertLastDayOfMonth($this->getSecondaryDayOfMonth())) - $last_pay_period_end_date; Debug::text('Primary Date Offset: ' . TTDate::getDays($primary_date_offset) . ' Secondary Date Offset: ' . TTDate::getDays($secondary_date_offset), __FILE__, __LINE__, __METHOD__, 10); if ($primary_date_offset <= $secondary_date_offset) { $insert_pay_period = 1; $primary = TRUE; $last_pay_period_end_date = TTDate::getDateOfNextDayOfMonth($last_pay_period_end_date, NULL, $this->convertLastDayOfMonth($this->getPrimaryDayOfMonth())); } else { $insert_pay_period = 2; $primary = FALSE; $last_pay_period_end_date = TTDate::getDateOfNextDayOfMonth($last_pay_period_end_date, NULL, $this->convertLastDayOfMonth($this->getSecondaryDayOfMonth())); } $last_pay_period_end_date = TTDate::getBeginDayEpoch($last_pay_period_end_date); } unset($tmp_last_pay_period_end_day_of_month); Debug::text('cLast Pay Period End Date: ' . TTDate::getDate('DATE+TIME', $last_pay_period_end_date) . ' (' . $last_pay_period_end_date . ') Primary: ' . (int) $primary, __FILE__, __LINE__, __METHOD__, 10); $start_date = $last_pay_period_end_date + 1; if ($primary == TRUE) { $end_date = TTDate::getBeginDayEpoch(TTDate::getDateOfNextDayOfMonth($start_date, NULL, $this->convertLastDayOfMonth($this->getSecondaryDayOfMonth()))) - 1; $transaction_date = TTDate::getMiddleDayEpoch(TTDate::getDateOfNextDayOfMonth(TTDate::getMiddleDayEpoch($end_date), NULL, $this->convertLastDayOfMonth($this->getPrimaryTransactionDayOfMonth()))); } else { $end_date = TTDate::getBeginDayEpoch(TTDate::getDateOfNextDayOfMonth($start_date, NULL, $this->convertLastDayOfMonth($this->getPrimaryDayOfMonth()))) - 1; $transaction_date = TTDate::getMiddleDayEpoch(TTDate::getDateOfNextDayOfMonth(TTDate::getMiddleDayEpoch($end_date), NULL, $this->convertLastDayOfMonth($this->getSecondaryTransactionDayOfMonth()))); } break; case 50: //Monthly $start_date = $last_pay_period_end_date + 1; $end_date = TTDate::getDateOfNextDayOfMonth($start_date + 86400, NULL, $this->convertLastDayOfMonth($this->getPrimaryDayOfMonth())); //Use Begin Day Epoch to nullify DST issues. $end_date = TTDate::getBeginDayEpoch(TTDate::getBeginMinuteEpoch($end_date)) - 1; $transaction_date = TTDate::getMiddleDayEpoch(TTDate::getDateOfNextDayOfMonth($end_date, NULL, $this->convertLastDayOfMonth($this->getPrimaryTransactionDayOfMonth()))); break; } if ($this->getDayStartTime() != 0) { Debug::text('Daily Start Time is set, adjusting End Date by: ' . TTDate::getHours($this->getDayStartTime()) . ' Start Date: ' . TTDate::getDate('DATE+TIME', $start_date), __FILE__, __LINE__, __METHOD__, 10); //We already account for DayStartTime in weekly/bi-weekly start_date cases above, so skip applying it again here. if ($this->getType() != 10 and $this->getType() != 20) { $start_date = $start_date + $this->getDayStartTime(); } $end_date = $end_date + $this->getDayStartTime(); //Need to do this, otherwise transaction date could be earlier then end date. $transaction_date = $transaction_date + $this->getDayStartTime(); } Debug::text('aStart Date(' . $start_date . '): ' . TTDate::getDate('DATE+TIME', $start_date), __FILE__, __LINE__, __METHOD__, 10); Debug::text('aEnd Date(' . $end_date . '): ' . TTDate::getDate('DATE+TIME', $end_date), __FILE__, __LINE__, __METHOD__, 10); Debug::text('aPay Date(' . $transaction_date . '): ' . TTDate::getDate('DATE+TIME', $transaction_date), __FILE__, __LINE__, __METHOD__, 10); //Handle last day of the month flag for primary and secondary dates here if ($this->getType() == 30 and ($insert_pay_period == 1 and ($this->getPrimaryDayOfMonth() == 31 or $this->getPrimaryDayOfMonth() == -1) or $insert_pay_period == 2 and ($this->getSecondaryDayOfMonth() == 31 or $this->getSecondaryDayOfMonth() == -1)) or $this->getType() == 50 and ($this->getPrimaryDayOfMonth() == 31 or $this->getPrimaryDayOfMonth() == -1)) { Debug::text('Last day of the month set for start date: ', __FILE__, __LINE__, __METHOD__, 10); if ($this->getDayStartTime() > 0) { //Minus one day, THEN add daily start time, otherwise it will go past the month boundary $end_date = TTDate::getEndMonthEpoch($end_date) - 86400 + $this->getDayStartTime(); //End month epoch is 23:59:59, so don't minus one. } else { $end_date = TTDate::getEndMonthEpoch($end_date) + $this->getDayStartTime(); //End month epoch is 23:59:59, so don't minus one. } } //Handle "last day of the month" for transaction dates. if ($this->getPrimaryDayOfMonth() == 31 or $this->getPrimaryDayOfMonth() == -1) { //Debug::text('LDOM set for Primary: ', __FILE__, __LINE__, __METHOD__, 10); $transaction_date = TTDate::getEndMonthEpoch($transaction_date); } //Handle "always business day" flag for transaction dates here. if ($this->getTransactionDateBusinessDay() == TRUE) { $transaction_date = $this->getTransactionBusinessDay($transaction_date); } if ($transaction_date < $end_date) { $transaction_date = $end_date; } Debug::text('Start Date: ' . TTDate::getDate('DATE+TIME', $start_date), __FILE__, __LINE__, __METHOD__, 10); Debug::text('End Date: ' . TTDate::getDate('DATE+TIME', $end_date), __FILE__, __LINE__, __METHOD__, 10); Debug::text('Pay Date: ' . TTDate::getDate('DATE+TIME', $transaction_date), __FILE__, __LINE__, __METHOD__, 10); Debug::text("<br><br>\n\n", __FILE__, __LINE__, __METHOD__, 10); $this->next_start_date = $start_date; $this->next_end_date = $end_date; $this->next_transaction_date = $transaction_date; //Its a primary pay period if ($insert_pay_period == 1) { $this->next_primary = TRUE; } else { $this->next_primary = FALSE; } return TRUE; }
public static function calculateTimeOnEachDayBetweenRange($start_epoch, $end_epoch) { if (TTDate::doesRangeSpanMidnight($start_epoch, $end_epoch) == TRUE) { $total_before_first_midnight = TTDate::getEndDayEpoch($start_epoch) + 1 - $start_epoch; if ($total_before_first_midnight > 0) { $retval[TTDate::getBeginDayEpoch($start_epoch)] = $total_before_first_midnight; } $loop_start = TTDate::getEndDayEpoch($start_epoch) + 1; $loop_end = TTDate::getBeginDayEpoch($end_epoch); for ($x = $loop_start; $x < $loop_end; $x += 86400) { $retval[TTDate::getBeginDayEpoch($x)] = 86400; } $total_after_last_midnight = $end_epoch - TTDate::getBeginDayEpoch($end_epoch); if ($total_after_last_midnight > 0) { $retval[TTDate::getBeginDayEpoch($end_epoch)] = $total_after_last_midnight; } } else { $retval = array(TTDate::getBeginDayEpoch($start_epoch) => $end_epoch - $start_epoch); } return $retval; }
function _outputPDFSchedule($format) { Debug::Text(' Format: ' . $format, __FILE__, __LINE__, __METHOD__, 10); $current_company = $this->getUserObject()->getCompanyObject(); if (!is_object($current_company)) { Debug::Text('Invalid company object...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; } $filter_data = $this->getFilterConfig(); $columns = Misc::trimSortPrefix($this->getOptions('columns')); $adjust_x = 10; $adjust_y = 10; //Required fields // 'first_name', 'last_name', 'branch', 'department', 'start_time', 'end_time' $start_week_day = 0; if (is_object($this->getUserObject()) and is_object($this->getUserObject()->getUserPreferenceObject())) { $start_week_day = $this->getUserObject()->getUserPreferenceObject()->getStartWeekDay(); } //Debug::Arr($this->form_data, 'Form Data: ', __FILE__, __LINE__, __METHOD__,10); //Debug::Arr($this->data, 'Data: ', __FILE__, __LINE__, __METHOD__,10); $this->getProgressBarObject()->start($this->getAMFMessageID(), 2, NULL, TTi18n::getText('Querying Database...')); //Iterations need to be 2, otherwise progress bar is not created. $this->getProgressBarObject()->set($this->getAMFMessageID(), 2); $sf = TTNew('ScheduleFactory'); //getScheduleArray() doesn't accept pay_period_ids, so no data is returned if a time period of "last_pay_period" is selected. if (isset($filter_data['pay_period_id'])) { unset($filter_data['pay_period_id']); $filter_data['start_date'] = TTDate::getBeginDayEpoch(time() - 86400 * 14); //Default to the last 14days. $filter_data['end_date'] = TTDate::getEndDayEpoch(time() - 86400); } $raw_schedule_shifts = $sf->getScheduleArray($filter_data); if (is_array($raw_schedule_shifts)) { //Debug::Arr($raw_schedule_shifts, 'Raw Schedule Shifts: ', __FILE__, __LINE__, __METHOD__,10); $this->getProgressBarObject()->start($this->getAMFMessageID(), count($raw_schedule_shifts, COUNT_RECURSIVE), NULL, TTi18n::getText('Retrieving Data...')); $key = 0; foreach ($raw_schedule_shifts as $date_stamp => $day_schedule_shifts) { foreach ($day_schedule_shifts as $shift_arr) { $this->form_data['schedule_by_branch'][$shift_arr['branch']][$shift_arr['department']][$shift_arr['last_name'] . $shift_arr['first_name']][$date_stamp][] = $shift_arr; //Need to be able to sort employees by last name first. Use names as keys instead of user_ids. //$this->form_data['schedule_by_user'][$shift_arr['user_id']][$date_stamp][$shift_arr['branch']][$shift_arr['department']][] = $shift_arr; $this->form_data['schedule_by_user'][$shift_arr['last_name'] . '_' . $shift_arr['first_name']][$date_stamp][$shift_arr['branch']][$shift_arr['department']][] = $shift_arr; if (!isset($this->form_data['dates']['start_date']) or $this->form_data['dates']['start_date'] > $date_stamp) { $this->form_data['dates']['start_date'] = $date_stamp; } if (!isset($this->form_data['dates']['end_date']) or $this->form_data['dates']['end_date'] < $date_stamp) { $this->form_data['dates']['end_date'] = $date_stamp; } $this->getProgressBarObject()->set($this->getAMFMessageID(), $key); $key++; } } unset($date_stamp, $raw_schedule_shifts, $day_schedule_shifts); } else { Debug::Text('No schedule shifts returned...', __FILE__, __LINE__, __METHOD__, 10); } //Initialize array element if it doesn't exist to prevent PHP warning. if (!isset($this->form_data['schedule_by_user'])) { $this->form_data['schedule_by_user'] = array(); } //Debug::Arr($this->form_data['schedule_by_branch'], '2Raw Schedule Shifts: ', __FILE__, __LINE__, __METHOD__,10); //Debug::Arr($this->form_data['dates'], 'Dates: ', __FILE__, __LINE__, __METHOD__,10); //If pay periods are requested, we need to convert those to start/end dates. if (isset($this->form_data['dates']['start_date']) and isset($this->form_data['dates']['end_date']) and (!isset($filter_data['start_date']) or !isset($filter_data['end_date']))) { $filter_data['start_date'] = strtotime($this->form_data['dates']['start_date']); $filter_data['end_date'] = strtotime($this->form_data['dates']['end_date']); } if (isset($filter_data['start_date']) and isset($filter_data['end_date'])) { $pdf_created_date = time(); $this->pdf = new TTPDF($this->config['other']['page_orientation'], 'mm', $this->config['other']['page_format'], $this->getUserObject()->getCompanyObject()->getEncoding()); $this->pdf->SetAuthor(APPLICATION_NAME); $this->pdf->SetTitle($this->title); $this->pdf->SetSubject(APPLICATION_NAME . ' ' . TTi18n::getText('Report')); $this->pdf->setMargins($this->config['other']['left_margin'], $this->config['other']['top_margin'], $this->config['other']['right_margin']); //Debug::Arr($this->config['other'], 'Margins: ', __FILE__, __LINE__, __METHOD__,10); $this->pdf->SetAutoPageBreak(FALSE, 0); $this->pdf->SetFont($this->config['other']['default_font'], '', $this->_pdf_fontSize(10)); //Debug::Arr($this->form_data, 'zabUser Raw Data: ', __FILE__, __LINE__, __METHOD__,10); $calendar_array = TTDate::getCalendarArray($filter_data['start_date'], $filter_data['end_date'], $start_week_day); //Debug::Arr($calendar_array, 'Calendar Array: ', __FILE__, __LINE__, __METHOD__,10); switch ($format) { case 'pdf_schedule_group': case 'pdf_schedule_group_print': case 'pdf_schedule_group_pagebreak': case 'pdf_schedule_group_pagebreak_print': // // Group - Separate (branch/department on their own pages) // //Start displaying dates/times here. Start with header. $column_widths = array('line' => 5, 'label' => 30, 'day' => ($this->pdf->getPageWidth() - $this->config['other']['left_margin'] - $this->config['other']['right_margin'] - 30) / 7); if (isset($this->form_data['schedule_by_branch'])) { $this->pdf->AddPage($this->config['other']['page_orientation'], 'Letter'); $n = 0; ksort($this->form_data['schedule_by_branch']); foreach ($this->form_data['schedule_by_branch'] as $branch => $level_2) { ksort($level_2); foreach ($level_2 as $department => $level_3) { ksort($level_3); if ($format == 'pdf_schedule_group_pagebreak' or $format == 'pdf_schedule_group_pagebreak_print') { //Insert page breaks after each branch/department in this mode. if ($n > 0) { $this->pdf->AddPage($this->config['other']['page_orientation'], 'Letter'); } $page_break = TRUE; } else { $page_break = $n == 0 ? TRUE : $this->scheduleCheckPageBreak(30, TRUE); } $this->scheduleHeader($branch, $department, NULL, $page_break); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); //FIXME: Find a better way to determine how many iterations there will be in this loop. $this->getProgressBarObject()->start($this->getAMFMessageID(), count($calendar_array), NULL, TTi18n::getText('Generating Schedules...')); $key = 0; $i = 0; foreach ($calendar_array as $calendar_day) { if ($i % 7 == 0) { $calendar_week_array = array_slice($calendar_array, $i, 7); if ($i != 0) { $this->scheduleFooterWeek(); } $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format); $s = 0; foreach ($level_3 as $user_id => $user_schedule) { if ($this->_pdf_checkMaximumPageLimit() == FALSE) { Debug::Text('Exceeded maximum page count...', __FILE__, __LINE__, __METHOD__, 10); //Exceeded maximum pages, stop processing. $this->_pdf_displayMaximumPageLimitError(); break 4; } //Handle page break. $page_break_height = 5; if ($this->scheduleCheckPageBreak($page_break_height, TRUE) == TRUE) { $this->scheduleHeader($branch, $department); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format, TRUE); } if ($s % 2 == 0) { $this->pdf->setFillColor(255, 255, 255); } else { $this->pdf->setFillColor(245, 245, 245); } if ($this->scheduleUserWeek($user_schedule, $calendar_week_array, $start_week_day, $column_widths, $format, $key) == TRUE) { $s++; } } } $this->getProgressBarObject()->set($this->getAMFMessageID(), $key); if ($key % 25 == 0 and $this->isSystemLoadValid() == FALSE) { return FALSE; } $key++; $i++; } $this->scheduleFooterWeek($column_widths); $this->scheduleFooter(); } $n++; } } else { $this->scheduleNoData(); } break; case 'pdf_schedule_group_combined': case 'pdf_schedule_group_combined_print': ksort($this->form_data['schedule_by_user']); //Start displaying dates/times here. Start with header. $column_widths = array('line' => 5, 'label' => 30, 'day' => ($this->pdf->getPageWidth() - $this->config['other']['left_margin'] - $this->config['other']['right_margin'] - 30) / 7); $this->getProgressBarObject()->start($this->getAMFMessageID(), count($this->form_data['schedule_by_user']) * (count($calendar_array) / 7), NULL, TTi18n::getText('Generating Schedules...')); $this->pdf->AddPage($this->config['other']['page_orientation'], 'Letter'); $this->scheduleHeader(); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); $key = 0; $i = 0; foreach ($calendar_array as $calendar_day) { if ($i % 7 == 0) { $calendar_week_array = array_slice($calendar_array, $i, 7); if ($i != 0) { $this->scheduleFooterWeek(); } $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format); foreach ($this->form_data['schedule_by_user'] as $user_id => $user_schedule) { if ($this->_pdf_checkMaximumPageLimit() == FALSE) { Debug::Text('Exceeded maximum page count...', __FILE__, __LINE__, __METHOD__, 10); //Exceeded maximum pages, stop processing. $this->_pdf_displayMaximumPageLimitError(); break 2; } $s = 0; //Handle page break. if ($this->scheduleCheckPageBreak(5, TRUE) == TRUE) { $this->scheduleFooterWeek($column_widths); $this->scheduleHeader(); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format, TRUE); } $this->pdf->setFillColor(255, 255, 255); if ($this->scheduleUserWeek($user_schedule, $calendar_week_array, $start_week_day, $column_widths, $format, $key) == TRUE) { $s++; } $this->getProgressBarObject()->set($this->getAMFMessageID(), $key); if ($key % 25 == 0 and $this->isSystemLoadValid() == FALSE) { return FALSE; } $key++; } $this->scheduleFooterWeek($column_widths); } $i++; } $this->scheduleFooter(); break; case 'pdf_schedule': case 'pdf_schedule_print': ksort($this->form_data['schedule_by_user']); //Start displaying dates/times here. Start with header. $column_widths = array('line' => 5, 'label' => 0, 'day' => ($this->pdf->getPageWidth() - $this->config['other']['left_margin'] - $this->config['other']['right_margin'] - 0) / 7); if (isset($this->form_data['schedule_by_user'])) { $this->getProgressBarObject()->start($this->getAMFMessageID(), count($this->form_data['schedule_by_user']) * (count($calendar_array) / 7), NULL, TTi18n::getText('Generating Schedules...')); $key = 0; foreach ($this->form_data['schedule_by_user'] as $user_full_name => $user_schedule) { $this->pdf->AddPage($this->config['other']['page_orientation'], 'Letter'); $split_name = explode('_', $user_full_name); $this->scheduleHeader(NULL, NULL, $split_name[1] . ' ' . $split_name[0]); unset($split_name); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); $i = 0; foreach ($calendar_array as $calendar_day) { if ($i % 7 == 0) { if ($this->_pdf_checkMaximumPageLimit() == FALSE) { Debug::Text('Exceeded maximum page count...', __FILE__, __LINE__, __METHOD__, 10); //Exceeded maximum pages, stop processing. $this->_pdf_displayMaximumPageLimitError(); break 2; } $calendar_week_array = array_slice($calendar_array, $i, 7); if ($i != 0) { $this->scheduleFooterWeek(); } $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format); //Handle page break. $page_break_height = 5; if ($this->scheduleCheckPageBreak($page_break_height, TRUE) == TRUE) { $this->scheduleHeader(); $this->scheduleDayOfWeekNameHeader($start_week_day, $column_widths, $format); $this->scheduleWeekHeader($calendar_week_array, $column_widths, $format, TRUE); } $this->pdf->setFillColor(255, 255, 255); $this->scheduleUserWeek($user_schedule, $calendar_week_array, $start_week_day, $column_widths, $format, $key); } $this->getProgressBarObject()->set($this->getAMFMessageID(), $key); if ($key % 25 == 0 and $this->isSystemLoadValid() == FALSE) { return FALSE; } $key++; $i++; } $this->scheduleFooterWeek($column_widths); $this->scheduleFooter(); } } else { $this->scheduleNoData(); } break; } $output = $this->pdf->Output('', 'S'); return $output; } else { Debug::Text('No start/end date specified...', __FILE__, __LINE__, __METHOD__, 10); } Debug::Text('No data to return...', __FILE__, __LINE__, __METHOD__, 10); return FALSE; }
if ($permission->Check('schedule', 'view') == FALSE) { if ($permission->Check('schedule', 'view_child') == FALSE) { $permission_children_ids = array(); } if ($permission->Check('schedule', 'view_own')) { $permission_children_ids[] = $current_user->getId(); } $filter_data['permission_children_ids'] = $permission_children_ids; } $action = Misc::findSubmitButton(); switch ($action) { default: $user_ids = array(); if ($filter_data['start_date'] != '') { $start_date = $filter_data['start_date'] = TTDate::getBeginDayEpoch($filter_data['start_date']); $end_date = $filter_data['end_date'] = TTDate::getEndDayEpoch($start_date); } Debug::text(' Start Date: ' . TTDate::getDate('DATE+TIME', $start_date) . ' End Date: ' . TTDate::getDate('DATE+TIME', $end_date), __FILE__, __LINE__, __METHOD__, 10); $sf = TTnew('ScheduleFactory'); $raw_schedule_shifts = $sf->getScheduleArray($filter_data); if (is_array($raw_schedule_shifts)) { foreach ($raw_schedule_shifts as $day_epoch => $day_schedule_shifts) { foreach ($day_schedule_shifts as $day_schedule_shift) { $user_ids[] = $day_schedule_shift['user_id']; //$day_schedule_shift['is_owner'] = $permission->isOwner( $u_obj->getCreatedBy(), $u_obj->getId() ); //$day_schedule_shift['is_child'] = $permission->isChild( $u_obj->getId(), $permission_children_ids ); $day_schedule_shift['is_owner'] = $permission->isOwner($day_schedule_shift['user_created_by'], $day_schedule_shift['user_id']); $day_schedule_shift['is_child'] = $permission->isChild($day_schedule_shift['user_id'], $permission_children_ids); $tmp_schedule_shifts[$day_epoch][$day_schedule_shift['branch']][$day_schedule_shift['department']][] = $day_schedule_shift; //echo 'User ID: '. $day_schedule_shift['user_id'] .' Date: '. $day_epoch .' Total Time: '. ($day_schedule_shift['total_time']/3600) ."<br>\n"; if ($day_schedule_shift['status_id'] == 10) {
$max_hour = $max_hour + 2; } Debug::text(' bSetting Max Hour: ' . $max_hour, __FILE__, __LINE__, __METHOD__, 10); } if (TTDate::getDayOfMonth($day_schedule_shift['start_time']) != TTDate::getDayOfMonth($day_schedule_shift['end_time'] - 1)) { //-1 from end time to handle a 12:00AM end time without going to next day. Debug::text(' aSchedule Spans the Day boundary!', __FILE__, __LINE__, __METHOD__, 10); $day_schedule_shift['span_day'] = TRUE; $min_hour = 0; $max_hour = 24; } if ($day_schedule_shift['span_day'] == TRUE) { //Cut shift into two days. $tmp_schedule_shift_day1 = $tmp_schedule_shift_day2 = $day_schedule_shift; $tmp_schedule_shift_day1['span_day_split'] = TRUE; $tmp_schedule_shift_day1['end_time'] = TTDate::getEndDayEpoch($day_schedule_shift['start_time']) + 1; $tmp_schedule_shift_day2['start_time'] = TTDate::getBeginDayEpoch($day_schedule_shift['end_time']); $tmp_schedule_shift_day2['span_day_split'] = FALSE; $tmp_schedule_shifts[$day_epoch][$day_schedule_shift['branch']][$day_schedule_shift['department']][$day_schedule_shift['user_id']][] = $tmp_schedule_shift_day1; $tmp_schedule_shifts[$tmp_schedule_shift_day2['start_time']][$day_schedule_shift['branch']][$day_schedule_shift['department']][$day_schedule_shift['user_id']][] = $tmp_schedule_shift_day2; Debug::text(' Shift SPans the Day Boundary: First End Date: ' . TTDate::getDate('DATE+TIME', $tmp_schedule_shift_day1['end_time']) . ' Second Start Date: ' . TTDate::getDate('DATE+TIME', $tmp_schedule_shift_day2['start_time']), __FILE__, __LINE__, __METHOD__, 10); } else { $tmp_schedule_shifts[$day_epoch][$day_schedule_shift['branch']][$day_schedule_shift['department']][$day_schedule_shift['user_id']][] = $day_schedule_shift; } //$schedule_shifts[$day_epoch][] = $day_schedule_shift; if ($day_schedule_shift['status_id'] == 10) { //Working if (isset($schedule_shift_totals[$day_epoch]['total_time'])) { $schedule_shift_totals[$day_epoch]['total_time'] += $day_schedule_shift['total_time']; } else { $schedule_shift_totals[$day_epoch]['total_time'] = $day_schedule_shift['total_time'];
$pay_period_ids[] = $pay_period_obj->getId(); $pay_period_end_dates[$pay_period_obj->getId()] = $pay_period_obj->getEndDate(); if ($pp == 0) { $default_transaction_start_date = $pay_period_obj->getEndDate(); $default_transaction_end_date = $pay_period_obj->getTransactionDate() + 86400; } $pp++; } $pplf = new PayPeriodListFactory(); $pay_period_options = $pplf->getByIdListArray($pay_period_ids, NULL, array('start_date' => 'desc')); } if (isset($filter_data['transaction_start_date'])) { $filter_data['transaction_start_date'] = TTDate::getBeginDayEpoch(TTDate::parseDateTime($filter_data['transaction_start_date'])); } if (isset($filter_data['transaction_end_date'])) { $filter_data['transaction_end_date'] = TTDate::getEndDayEpoch(TTDate::parseDateTime($filter_data['transaction_end_date'])); } $filter_data = Misc::preSetArrayValues($filter_data, array('include_user_ids', 'exclude_user_ids', 'user_status_ids', 'group_ids', 'branch_ids', 'department_ids', 'user_title_ids', 'currency_ids', 'pay_period_ids', 'column_ids'), array()); //Get Permission Hierarchy Children first, as this can be used for viewing, or editing. $permission_children_ids = array(); if ($permission->Check('pay_stub', 'view') == FALSE) { $hlf = new HierarchyListFactory(); $permission_children_ids = $hlf->getHierarchyChildrenByCompanyIdAndUserIdAndObjectTypeID($current_company->getId(), $current_user->getId()); Debug::Arr($permission_children_ids, 'Permission Children Ids:', __FILE__, __LINE__, __METHOD__, 10); if ($permission->Check('pay_stub', 'view_child') == FALSE) { $permission_children_ids = array(); } if ($permission->Check('pay_stub', 'view_own')) { $permission_children_ids[] = $current_user->getId(); } $filter_data['permission_children_ids'] = $permission_children_ids;
function setLastDate($epoch) { $epoch = trim($epoch); //Include the entire day. //$epoch = TTDate::getBeginDayEpoch( $epoch ) + (86400-120); $epoch = TTDate::getEndDayEpoch($epoch); if ($this->Validator->isDate('last_date', $epoch, TTi18n::gettext('Invalid last date'))) { $this->data['last_date'] = $epoch; return TRUE; } return FALSE; }
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); //Get user date info $udlf = new 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()) { return FALSE; } } else { return FALSE; } //Since we are not usng demerits yet, just always delete exceptions and re-calculate them $elf = new ExceptionListFactory(); $elf->getByUserDateID($user_date_id); if ($elf->getRecordCount() > 0) { foreach ($elf as $e_obj) { Debug::text(' Deleting Exception: ' . $e_obj->getID(), __FILE__, __LINE__, __METHOD__, 10); $e_obj->Delete(); } } //Get all Punches on this date for this user. $plf = new PunchListFactory(); $plf->getByUserDateId($user_date_id); if ($plf->getRecordCount() > 0) { Debug::text(' Found Punches: ' . $plf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10); } $slf = new 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. //Get all active exceptions. $eplf = new 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. if ($plf->getRecordCount() == 0) { if ($slf->getRecordCount() > 0) { foreach ($slf as $s_obj) { if ($s_obj->getStatus() == 10 and TTDate::getBeginDayEpoch($s_obj->getStartTime()) - TTDate::getBeginDayEpoch(TTDate::getTime()) <= 0) { $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } else { Debug::text(' NOT Scheduled', __FILE__, __LINE__, __METHOD__, 10); } } break; case 's2': //Not Scheduled $schedule_total_time = 0; if ($slf->getRecordCount() == 0) { if ($plf->getRecordCount() > 0) { Debug::text(' Worked when wasnt scheduled', __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } else { Debug::text(' IS Scheduled', __FILE__, __LINE__, __METHOD__, 10); } 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 foreach ($plf as $p_obj) { if ($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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchID($p_obj->getID()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } else { Debug::text(' NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10); } } } } break; case 's4': //In Late if ($plf->getRecordCount() > 0) { foreach ($plf as $p_obj) { if ($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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchID($p_obj->getID()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } 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 foreach ($plf as $p_obj) { if ($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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchID($p_obj->getID()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } else { Debug::text(' NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10); } } } } break; case 's6': //Out Late if ($plf->getRecordCount() > 0) { foreach ($plf as $p_obj) { if ($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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchID($p_obj->getID()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } else { Debug::text(' NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10); } } } } 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() < time() - 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('aFound Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10); if ($punch_pair[0]['status_id'] == 20) { //Missing In Punch Debug::text('bFound Missing In Punch: ', __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchControlID($punch_pair[0]['punch_control_id']); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } 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); if ($type_id == 5 and $p_obj->getTimeStamp() < time() - self::$premature_delay) { $type_id = 50; } $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID()); } if (isset($punch_pairs)) { 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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setPunchControlID($punch_pair[0]['punch_control_id']); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } 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() < time() - 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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); //$ef->setPunchControlID( $invalid_punch_arr['punch_id'] ); $ef->setPunchID($invalid_punch_arr['punch_id']); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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() < time() - 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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); //$ef->setPunchControlID( $invalid_punch_arr['punch_id'] ); $ef->setPunchID($invalid_punch_arr['punch_id']); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } unset($invalid_punch_arr); } else { Debug::text('Lunch Punches match up.', __FILE__, __LINE__, __METHOD__, 10); } unset($invalid_punches); } } break; case 's7': //Over Scheduled Hours if ($plf->getRecordCount() > 0) { //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 = new UserDateTotalListFactory(); //Take into account auto-deduct/add meal policies //$udtlf->getByUserDateIdAndStatus( $user_date_id, 20 ); $udtlf->getByUserDateIdAndStatusAndType($user_date_id, 10, 10); if ($udtlf->getRecordCount() > 0) { foreach ($udtlf as $udt_obj) { $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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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) { //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 = new UserDateTotalListFactory(); //Take into account auto-deduct/add meal policies //$udtlf->getByUserDateIdAndStatus( $user_date_id, 20 ); $udtlf->getByUserDateIdAndStatusAndType($user_date_id, 10, 10); if ($udtlf->getRecordCount() > 0) { foreach ($udtlf as $udt_obj) { $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(time() - self::$premature_delay)) { $type_id = 50; } $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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) { //This ONLY takes in to account WORKED hours, not paid absence hours. $daily_total_time = 0; //Get daily total time. $udtlf = new UserDateTotalListFactory(); //Take into account auto-deduct/add meal policies $udtlf->getByUserDateIdAndStatusAndType($user_date_id, 10, 10); if ($udtlf->getRecordCount() > 0) { foreach ($udtlf as $udt_obj) { $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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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) { //Get Pay Period Schedule info 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; if (strtolower($ep_obj->getType()) == 's9') { $tmp_slf = new ScheduleListFactory(); $tmp_slf->getByUserIdAndStartDateAndEndDate($user_date_obj->getUser(), TTDate::getBeginWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id), $user_date_obj->getDateStamp()); if ($tmp_slf->getRecordCount() > 0) { foreach ($tmp_slf as $s_obj) { $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 = new 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); 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_total_time > 0 and $weekly_total_time > $weekly_scheduled_total_time + $ep_obj->getGrace()) { Debug::text(' Worked Over Weekly Hours', __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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 = new 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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); if (isset($time_stamp_arr['punch_id'])) { $ef->setPunchID($time_stamp_arr['punch_id']); } $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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 shift though. //Also ignore this exception if the lunch is auto-deduct. $daily_total_time = 0; $udtlf = new UserDateTotalListFactory(); $udtlf->getByUserDateIdAndStatus($user_date_id, 20); if ($udtlf->getRecordCount() > 0) { foreach ($udtlf as $udt_obj) { $daily_total_time += $udt_obj->getTotalTime(); } } Debug::text('Day Total Time: ' . $daily_total_time, __FILE__, __LINE__, __METHOD__, 10); if ($daily_total_time > 0) { //Check for lunch punch. $lunch_punch = FALSE; foreach ($plf as $p_obj) { if ($p_obj->getType() == 20) { Debug::text('Found Lunch Punch: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10); $lunch_punch = TRUE; break; } } if ($lunch_punch == FALSE) { Debug::text('DID NOT Find Lunch Punch... Checking meal policies. ', __FILE__, __LINE__, __METHOD__, 10); //Use scheduled meal policy first. 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); if ($daily_total_time > $s_obj->getSchedulePolicyObject()->getMealPolicyObject()->getTriggerTime()) { Debug::text('Daily Total Time is After Schedule Meal Policy Trigger Time: ', __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } 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 = new MealPolicyListFactory(); $mplf->getByPolicyGroupUserId($user_date_obj->getUser()); if ($mplf->getRecordCount() > 0) { Debug::text('Found UnScheduled Meal Policy...', __FILE__, __LINE__, __METHOD__, 10); $m_obj = $mplf->getCurrent(); if ($daily_total_time > $m_obj->getTriggerTime() and $m_obj->getType() == 20) { Debug::text('Daily Total Time is After Schedule Meal Policy Trigger Time: ' . $m_obj->getTriggerTime(), __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } else { Debug::text('Auto-deduct meal policy, ignorning this exception.', __FILE__, __LINE__, __METHOD__, 10); } } else { //There is no meal policy or schedule policy with a meal policy assigned to it //With out this we could still apply No Lunch exceptions, but they will happen even on //a 2minute shift. Debug::text('No meal policy, applying No Lunch exception.', __FILE__, __LINE__, __METHOD__, 10); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } else { Debug::text('Found Lunch Punch... Ignoring this exception. ', __FILE__, __LINE__, __METHOD__, 10); } } } 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 = new 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()->getBreakPolicyObject(); $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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); if (isset($time_stamp_arr['punch_id'])) { $ef->setPunchID($time_stamp_arr['punch_id']); } $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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); 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 = new 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()->getBreakPolicyObject(); $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany()); } else { $bplf->getByPolicyGroupUserId($user_date_obj->getUser()); } 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); $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); if (isset($time_stamp_arr['punch_id']) and strtolower($ep_obj->getType()) == 'b3') { $ef->setPunchID($time_stamp_arr['punch_id']); } $ef->setType($type_id); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } else { Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10); } } } } } break; case 'j1': //Not Allowed on Job if ($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 = new JobListFactory(); $jlf->getById($p_obj->getPunchControlObject()->getJob()); if ($jlf->getRecordCount() > 0) { $j_obj = $jlf->getCurrent(); if ($j_obj->isAllowedUser($user_date_obj->getUser()) == FALSE) { $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setPunchControlId($p_obj->getPunchControlId()); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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 ($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 = new JobListFactory(); $jlf->getById($p_obj->getPunchControlObject()->getJob()); if ($jlf->getRecordCount() > 0) { $j_obj = $jlf->getCurrent(); if ($j_obj->isAllowedItem($p_obj->getPunchControlObject()->getJobItem()) == FALSE) { $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setPunchControlId($p_obj->getPunchControlId()); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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 ($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 = new 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()) { $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setPunchControlId($p_obj->getPunchControlId()); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } 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 ($plf->getRecordCount() > 0) { foreach ($plf as $p_obj) { //In punches only if ($p_obj->getStatus() == 10 and is_object($p_obj->getPunchControlObject()) and ($p_obj->getPunchControlObject()->getJob() == '' or $p_obj->getPunchControlObject()->getJob() == 0 or $p_obj->getPunchControlObject()->getJob() == FALSE or $p_obj->getPunchControlObject()->getJobItem() == '' or $p_obj->getPunchControlObject()->getJobItem() == 0 or $p_obj->getPunchControlObject()->getJobItem() == FALSE)) { $ef = new ExceptionFactory(); $ef->setUserDateID($user_date_id); $ef->setExceptionPolicyID($ep_obj->getId()); $ef->setType($type_id); $ef->setPunchControlId($p_obj->getPunchControlId()); $ef->setPunchId($p_obj->getId()); $ef->setEnableDemerits(TRUE); if ($ef->isValid()) { if ($enable_premature_exceptions == TRUE) { $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, $ep_obj); } $ef->Save(); } } } } break; default: Debug::text('BAD, should never get here: ', __FILE__, __LINE__, __METHOD__, 10); break; } } } $profiler->stopTimer("ExceptionPolicy::calcExceptions()"); return TRUE; }