function inApplyFrequencyWindow($pay_period_start_date, $pay_period_end_date, $hire_date = NULL, $termination_date = NULL, $birth_date = NULL)
 {
     if ($this->getApplyFrequency() == FALSE or $this->getApplyFrequency() == 10) {
         //Each pay period
         return TRUE;
     }
     $frequency_criteria = array('month' => $this->getApplyFrequencyMonth(), 'day_of_month' => $this->getApplyFrequencyDayOfMonth(), 'quarter_month' => $this->getApplyFrequencyQuarterMonth());
     $specific_date = FALSE;
     $frequency_id = $this->getApplyFrequency();
     switch ($this->getApplyFrequency()) {
         case 100:
             //Hire Date
             $frequency_criteria['date'] = $hire_date;
             $frequency_id = 100;
             //Specific date
             break;
         case 110:
             //Hire Date anniversary.
             $frequency_criteria['month'] = TTDate::getMonth($hire_date);
             $frequency_criteria['day_of_month'] = TTDate::getDayOfMonth($hire_date);
             $frequency_id = 20;
             //Annually
             break;
         case 120:
             $frequency_criteria['date'] = $termination_date;
             $frequency_id = 100;
             //Specific date
             break;
         case 130:
             //Birth Date anniversary.
             $frequency_criteria['month'] = TTDate::getMonth($birth_date);
             $frequency_criteria['day_of_month'] = TTDate::getDayOfMonth($birth_date);
             $frequency_id = 20;
             //Annually
             break;
     }
     $retval = TTDate::inApplyFrequencyWindow($frequency_id, $pay_period_start_date, $pay_period_end_date, $frequency_criteria);
     Debug::Arr($frequency_criteria, 'Frequency: ' . $this->getApplyFrequency() . ' Retval: ' . (int) $retval, __FILE__, __LINE__, __METHOD__, 10);
     return $retval;
 }
 function calcAccrualPolicyTime($u_obj, $epoch, $offset, $pps_obj, $pay_period_arr, $accrual_balance, $update_records = TRUE)
 {
     $retval = 0;
     Debug::Text('User: '******' Status: ' . $u_obj->getStatus() . ' Epoch: ' . TTDate::getDate('DATE+TIME', $epoch), __FILE__, __LINE__, __METHOD__, 10);
     //Make sure only active employees accrue time *after* their hire date.
     //Will this negative affect Employees who may be on leave?
     if ($u_obj->getStatus() == 10 and $epoch >= $u_obj->getHireDate() and ($this->getMinimumEmployedDays() == 0 or TTDate::getDays($epoch - $u_obj->getHireDate()) >= $this->getMinimumEmployedDays())) {
         Debug::Text('  User is active and has been employed long enough.', __FILE__, __LINE__, __METHOD__, 10);
         $annual_pay_periods = $pps_obj->getAnnualPayPeriods();
         $in_apply_frequency_window = FALSE;
         $in_apply_rollover_window = FALSE;
         $pay_period_start_date = NULL;
         $accrual_amount = 0;
         if ($this->getType() == 30) {
             Debug::Text('  Accrual policy is hour based, real-time window.', __FILE__, __LINE__, __METHOD__, 10);
             //Hour based, apply frequency is real-time.
             $in_apply_frequency_window = TRUE;
         } else {
             if ($this->getApplyFrequency() == 10) {
                 $pay_period_dates = $this->getPayPeriodDatesFromArray($pay_period_arr, $epoch - $offset);
                 if (is_array($pay_period_dates)) {
                     Debug::Text('   Pay Period Start Date: ' . TTDate::getDate('DATE+TIME', $pay_period_dates['start_date']) . ' End Date: ' . TTDate::getDate('DATE+TIME', $pay_period_dates['end_date']), __FILE__, __LINE__, __METHOD__, 10);
                     if ($this->inApplyFrequencyWindow($epoch, $offset, $pay_period_dates['end_date']) == TRUE) {
                         $in_apply_frequency_window = TRUE;
                         $pay_period_start_date = $pay_period_dates['start_date'];
                         //Used for inRolloverFrequencyWindow
                     } else {
                         Debug::Text('  User not in Apply Frequency Window: ', __FILE__, __LINE__, __METHOD__, 10);
                     }
                 } else {
                     Debug::Arr($pay_period_dates, '   No Pay Period Dates Found.', __FILE__, __LINE__, __METHOD__, 10);
                 }
             } elseif ($this->inApplyFrequencyWindow($epoch, $offset, NULL, $u_obj->getHireDate()) == TRUE) {
                 Debug::Text('  User IS in NON-PayPeriod Apply Frequency Window.', __FILE__, __LINE__, __METHOD__, 10);
                 $in_apply_frequency_window = TRUE;
             } else {
                 Debug::Text('  User is not in Apply Frequency Window.', __FILE__, __LINE__, __METHOD__, 10);
                 $in_apply_frequency_window = FALSE;
             }
         }
         if ($this->inRolloverFrequencyWindow($epoch, $offset, $u_obj->getHireDate(), $pay_period_start_date)) {
             Debug::Text('   In rollover window...', __FILE__, __LINE__, __METHOD__, 10);
             $in_apply_rollover_window = TRUE;
         }
         if ($in_apply_frequency_window == TRUE or $in_apply_rollover_window == TRUE) {
             $milestone_obj = $this->getActiveMilestoneObject($u_obj, $epoch);
         }
         if ($in_apply_rollover_window == TRUE and (isset($milestone_obj) and is_object($milestone_obj))) {
             //Have accrual balance passed in for optimization
             //$accrual_balance = $this->getCurrentAccrualBalance( $u_obj->getID(), $this->getId() );
             //Handle maximum rollover adjustments before continuing.
             if ($accrual_balance > $milestone_obj->getRolloverTime()) {
                 $rollover_accrual_adjustment = bcsub($milestone_obj->getRolloverTime(), $accrual_balance, 0);
                 Debug::Text('   Adding rollover adjustment of: ' . $rollover_accrual_adjustment, __FILE__, __LINE__, __METHOD__, 10);
                 //Check to make sure there isn't an identical entry already made.
                 //Ignore rollover adjustment is another adjustment of any amount has been made on the same day.
                 $alf = TTnew('AccrualListFactory');
                 if ($update_records == TRUE) {
                     $alf->getByCompanyIdAndUserIdAndAccrualPolicyIDAndTypeIDAndTimeStamp($u_obj->getCompany(), $u_obj->getID(), $this->getId(), 60, TTDate::getMiddleDayEpoch($epoch));
                 }
                 if ($alf->getRecordCount() == 0) {
                     //Get effective date, try to use the current milestone rollover date to make things more clear.
                     $current_milestone_rollover_date = $this->getCurrentMilestoneRolloverDate($epoch, $u_obj->getHireDate());
                     //If milestone rollover date comes after the current epoch, back date it by one year.
                     if ($current_milestone_rollover_date > $epoch) {
                         $current_milestone_rollover_date = mktime(0, 0, 0, TTDate::getMonth($current_milestone_rollover_date), TTDate::getDayOfMonth($current_milestone_rollover_date), TTDate::getYear($epoch) - 1);
                     }
                     if ($update_records == TRUE) {
                         //Don't round to the nearest minute, as that can cause too much error on weekly frequencies.
                         $af = TTnew('AccrualFactory');
                         $af->setUser($u_obj->getID());
                         $af->setType(60);
                         //Rollover Adjustment
                         $af->setAccrualPolicyID($this->getId());
                         $af->setAmount($rollover_accrual_adjustment);
                         $af->setTimeStamp(TTDate::getMiddleDayEpoch($current_milestone_rollover_date));
                         $af->setEnableCalcBalance(TRUE);
                         if ($af->isValid()) {
                             $af->Save();
                         }
                     } else {
                         Debug::Text('   NOT UPDATING RECORDS...', __FILE__, __LINE__, __METHOD__, 10);
                         $retval = $rollover_accrual_adjustment;
                     }
                     //Make sure we get updated balance after rollover adjustment was made.
                     $accrual_balance += $rollover_accrual_adjustment;
                     unset($current_milestone_rollover_date);
                 } else {
                     Debug::Text('   Found duplicate rollover accrual entry, skipping...', __FILE__, __LINE__, __METHOD__, 10);
                 }
             } else {
                 Debug::Text('   Balance hasnt exceeded rollover adjustment...', __FILE__, __LINE__, __METHOD__, 10);
             }
             unset($rollover_accrual_adjustment, $alf, $af);
         }
         if ($in_apply_frequency_window === TRUE) {
             if (isset($milestone_obj) and is_object($milestone_obj)) {
                 Debug::Text('  Found Matching Milestone, Accrual Rate: (ID: ' . $milestone_obj->getId() . ') ' . $milestone_obj->getAccrualRate() . '/year', __FILE__, __LINE__, __METHOD__, 10);
                 //Make sure we get updated balance after rollover adjustment was made.
                 //Have accrual balance passed in for optimization
                 //$accrual_balance = $this->getCurrentAccrualBalance( $u_obj->getID(), $this->getId() );
                 if ($accrual_balance < $milestone_obj->getMaximumTime()) {
                     $accrual_amount = $this->calcAccrualAmount($milestone_obj, 0, $annual_pay_periods);
                     if ($accrual_amount > 0) {
                         $new_accrual_balance = bcadd($accrual_balance, $accrual_amount);
                         //If Maximum time is set to 0, make that unlimited.
                         if ($milestone_obj->getMaximumTime() > 0 and $new_accrual_balance > $milestone_obj->getMaximumTime()) {
                             $accrual_amount = bcsub($milestone_obj->getMaximumTime(), $accrual_balance, 0);
                         }
                         Debug::Text('&nbsp;&nbsp; Min/Max Adjusted Accrual Amount: ' . $accrual_amount . ' Limits: Min: ' . $milestone_obj->getMinimumTime() . ' Max: ' . $milestone_obj->getMaximumTime(), __FILE__, __LINE__, __METHOD__, 10);
                         //Check to make sure there isn't an identical entry already made.
                         $alf = TTnew('AccrualListFactory');
                         if ($update_records == TRUE) {
                             $alf->getByCompanyIdAndUserIdAndAccrualPolicyIDAndTimeStampAndAmount($u_obj->getCompany(), $u_obj->getID(), $this->getId(), TTDate::getMiddleDayEpoch($epoch), $accrual_amount);
                         }
                         if ($alf->getRecordCount() == 0) {
                             if ($update_records == TRUE) {
                                 Debug::Text('&nbsp;&nbsp; UPDATING RECORDS...', __FILE__, __LINE__, __METHOD__, 10);
                                 //Round to nearest 1min
                                 $af = TTnew('AccrualFactory');
                                 $af->setUser($u_obj->getID());
                                 $af->setType(75);
                                 //Accrual Policy
                                 $af->setAccrualPolicyID($this->getId());
                                 $af->setAmount($accrual_amount);
                                 $af->setTimeStamp(TTDate::getMiddleDayEpoch($epoch));
                                 $af->setEnableCalcBalance(TRUE);
                                 if ($af->isValid()) {
                                     $af->Save();
                                 }
                             } else {
                                 Debug::Text('&nbsp;&nbsp; NOT UPDATING RECORDS...', __FILE__, __LINE__, __METHOD__, 10);
                                 $retval += $accrual_amount;
                             }
                         } else {
                             Debug::Text('&nbsp;&nbsp; Found duplicate accrual entry, skipping...', __FILE__, __LINE__, __METHOD__, 10);
                         }
                         unset($accrual_amount, $accrual_balance, $new_accrual_balance);
                     } else {
                         Debug::Text('&nbsp;&nbsp; Accrual Amount is 0...', __FILE__, __LINE__, __METHOD__, 10);
                     }
                 } else {
                     Debug::Text('&nbsp;&nbsp; Accrual Balance is outside Milestone Range. Skipping...', __FILE__, __LINE__, __METHOD__, 10);
                 }
             } else {
                 Debug::Text('&nbsp;&nbsp;DID NOT Find Matching Milestone.', __FILE__, __LINE__, __METHOD__, 10);
             }
             unset($milestone_obj);
         }
     } else {
         Debug::Text('&nbsp;&nbsp;User is not active (Status: ' . $u_obj->getStatus() . ') or has only been employed: ' . TTDate::getDays($epoch - $u_obj->getHireDate()) . ' Days, not enough. Hire Date: ' . TTDate::getDATE('DATE+TIME', $u_obj->getHireDate()), __FILE__, __LINE__, __METHOD__, 10);
     }
     if ($update_records == TRUE) {
         return TRUE;
     } else {
         Debug::Text('Retval: ' . $retval, __FILE__, __LINE__, __METHOD__, 10);
         return $retval;
     }
 }
 function _outputPayrollExport($format = NULL)
 {
     $setup_data = $this->getFormConfig();
     Debug::Text('Generating Payroll Export... Format: ' . $format, __FILE__, __LINE__, __METHOD__, 10);
     if (isset($setup_data['export_type'])) {
         Debug::Text('Export Type: ' . $setup_data['export_type'], __FILE__, __LINE__, __METHOD__, 10);
     } else {
         Debug::Text('No Export Type defined!', __FILE__, __LINE__, __METHOD__, 10);
         return FALSE;
     }
     Debug::Arr($setup_data, 'Setup Data: ', __FILE__, __LINE__, __METHOD__, 10);
     $rows = $this->data;
     //Debug::Arr($rows, 'PreData: ', __FILE__, __LINE__, __METHOD__,10);
     $file_name = strtolower(trim($setup_data['export_type'])) . '_' . date('Y_m_d') . '.txt';
     $mime_type = 'application/text';
     $data = NULL;
     switch (strtolower(trim($setup_data['export_type']))) {
         case 'adp':
             //ADP export format.
             //File format supports multiple rows per employee (file #) all using the same columns. No need to jump through nasty hoops to fit everything on row.
             $export_column_map = array('company_code' => 'Co Code', 'batch_id' => 'Batch ID', 'temp_dept' => 'Temp Dept', 'employee_number' => 'File #', 'regular_time' => 'Reg Hours', 'overtime' => 'O/T Hours', '3_code' => 'Hours 3 Code', '3_amount' => 'Hours 3 Amount', '4_code' => 'Hours 4 Code', '4_amount' => 'Hours 4 Amount');
             ksort($setup_data['adp']['columns']);
             $setup_data['adp']['columns'] = Misc::trimSortPrefix($setup_data['adp']['columns']);
             foreach ($setup_data['adp']['columns'] as $column_id => $column_data) {
                 $column_name = NULL;
                 if ($column_data['hour_column'] == 'regular_time') {
                     $export_data_map[$column_id] = 'regular_time';
                 } elseif ($column_data['hour_column'] == 'overtime') {
                     $export_data_map[$column_id] = 'overtime';
                 } elseif ($column_data['hour_column'] >= 3) {
                     $export_data_map[$column_id] = $column_data;
                 }
             }
             if (!isset($setup_data['adp']['company_code_value'])) {
                 $setup_data['adp']['company_code_value'] = NULL;
             }
             if (!isset($setup_data['adp']['batch_id_value'])) {
                 $setup_data['adp']['batch_id_value'] = NULL;
             }
             if (!isset($setup_data['adp']['temp_dept_value'])) {
                 $setup_data['adp']['temp_dept_value'] = NULL;
             }
             $company_code_column = Misc::trimSortPrefix($setup_data['adp']['company_code']);
             $batch_id_column = Misc::trimSortPrefix($setup_data['adp']['batch_id']);
             $temp_dept_column = Misc::trimSortPrefix($setup_data['adp']['temp_dept']);
             foreach ($rows as $row) {
                 $static_columns = array('company_code' => isset($row[$company_code_column]) ? $row[$company_code_column] : $setup_data['adp']['company_code_value'], 'batch_id' => isset($row[$batch_id_column]) ? $row[$batch_id_column] : $setup_data['adp']['batch_id_value'], 'temp_dept' => isset($row[$temp_dept_column]) ? $row[$temp_dept_column] : $setup_data['adp']['temp_dept_value'], 'employee_number' => str_pad($row['employee_number'], 6, 0, STR_PAD_LEFT));
                 foreach ($setup_data['adp']['columns'] as $column_id => $column_data) {
                     $column_data = Misc::trimSortPrefix($column_data, TRUE);
                     Debug::Text('ADP Column ID: ' . $column_id . ' Hour Column: ' . $column_data['hour_column'] . ' Code: ' . $column_data['hour_code'], __FILE__, __LINE__, __METHOD__, 10);
                     if (isset($row[$column_id]) and $column_data['hour_column'] != '0') {
                         foreach ($export_column_map as $export_column_id => $export_column_name) {
                             Debug::Arr($row, 'Row: Column ID: ' . $column_id . ' Export Column ID: ' . $export_column_id . ' Name: ' . $export_column_name, __FILE__, __LINE__, __METHOD__, 10);
                             if (($column_data['hour_column'] == $export_column_id or $column_data['hour_column'] . '_code' == $export_column_id) and !in_array($export_column_id, array('company_code', 'batch_id', 'temp_dept', 'employee_number'))) {
                                 if ((int) substr($export_column_id, 0, 1) > 0) {
                                     $tmp_row[$column_data['hour_column'] . '_code'] = $column_data['hour_code'];
                                     $tmp_row[$column_data['hour_column'] . '_amount'] = TTDate::getTimeUnit($row[$column_id], 20);
                                 } else {
                                     $tmp_row[$export_column_id] = TTDate::getTimeUnit($row[$column_id], 20);
                                 }
                                 //Break out every column onto its own row, that way its easier to handle multiple columns of the same type.
                                 $tmp_rows[] = array_merge($static_columns, $tmp_row);
                                 unset($tmp_row);
                             }
                         }
                     }
                 }
             }
             $file_name = 'EPI000000.csv';
             if (isset($tmp_rows)) {
                 //File format supports multiple entries per employee (file #) all using the same columns. No need to jump through nasty hoops to fit everyone one row.
                 $file_name = 'EPI' . $tmp_rows[0]['company_code'] . $tmp_rows[0]['batch_id'] . '.csv';
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'adp_old':
             //ADP export format.
             $file_name = 'EPI' . $setup_data['adp']['company_code'] . $setup_data['adp']['batch_id'] . '.csv';
             $export_column_map = array();
             $static_export_column_map = array('company_code' => 'Co Code', 'batch_id' => 'Batch ID', 'employee_number' => 'File #');
             $static_export_data_map = array('company_code' => $setup_data['adp']['company_code'], 'batch_id' => $setup_data['adp']['batch_id']);
             //
             //Format allows for multiple duplicate columns.
             //ie: Hours 3 Code, Hours 3 Amount, Hours 3 Code, Hours 3 Amount, ...
             //However, we can only have a SINGLE O/T Hours column.
             //We also need to combine hours with the same code together.
             //
             ksort($setup_data['adp']['columns']);
             $setup_data['adp']['columns'] = Misc::trimSortPrefix($setup_data['adp']['columns']);
             foreach ($setup_data['adp']['columns'] as $column_id => $column_data) {
                 $column_name = NULL;
                 if ($column_data['hour_column'] == 'regular_time') {
                     $column_name = 'Reg Hours';
                     $export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
                 } elseif ($column_data['hour_column'] == 'overtime') {
                     $column_name = 'O/T Hours';
                     $export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
                 } elseif ($column_data['hour_column'] >= 3) {
                     $column_name = 'Hours ' . $column_data['hour_column'] . ' Amount';
                     $export_column_map[$setup_data['adp']['columns'][$column_id]['hour_code'] . '_code'] = 'Hours ' . $column_data['hour_column'] . ' Code';
                     $export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
                 }
                 if ($column_name != '') {
                     $export_column_map[trim($setup_data['adp']['columns'][$column_id]['hour_code'])] = $column_name;
                 }
             }
             $export_column_map = Misc::prependArray($static_export_column_map, $export_column_map);
             //
             //Combine time from all columns with the same hours code.
             //
             $i = 0;
             foreach ($rows as $row) {
                 foreach ($static_export_column_map as $column_id => $column_name) {
                     if (isset($static_export_data_map[$column_id])) {
                         //Copy over static config values like company code/batch_id.
                         $tmp_rows[$i][$column_id] = $static_export_data_map[$column_id];
                     } elseif (isset($row[$column_id])) {
                         if (isset($static_export_column_map[$column_id])) {
                             //Copy over employee_number. (File #)
                             $tmp_rows[$i][$column_id] = $row[$column_id];
                         }
                     }
                 }
                 foreach ($export_data_map as $column_id => $column_name) {
                     if (!isset($tmp_rows[$i][$column_name])) {
                         $tmp_rows[$i][$column_name] = 0;
                     }
                     if (isset($row[$column_id])) {
                         $tmp_rows[$i][$column_name] += $row[$column_id];
                     }
                     $tmp_rows[$i][$column_name . '_code'] = $column_name;
                 }
                 $i++;
             }
             //Convert time from seconds to hours.
             $convert_unit_columns = array_keys($static_export_column_map);
             foreach ($tmp_rows as $row => $data) {
                 foreach ($data as $column_id => $column_data) {
                     //var_dump($column_id,$column_data);
                     if (is_int($column_data) and !in_array($column_id, $convert_unit_columns)) {
                         $tmp_rows[$row][$column_id] = TTDate::getTimeUnit($column_data, 20);
                     }
                 }
             }
             unset($row, $data, $column_id, $column_data);
             $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE);
             break;
         case 'paychex_preview_advanced_job':
             //PayChex Preview with job information
             unset($rows);
             //Ignore any existing timesheet summary data, we will be using our own job data below.
             //Debug::Arr($setup_data, 'PayChex Advanced Job Setup Data: ', __FILE__, __LINE__, __METHOD__,10);
             $config['columns'][] = 'employee_number';
             $config['columns'][] = 'date_stamp';
             $config['columns'] = array_merge($config['columns'], (array) $setup_data['paychex_preview_advanced_job']['job_columns']);
             $config['columns'][] = $setup_data['paychex_preview_advanced_job']['state_columns'];
             $config['columns'] += array_keys(Misc::trimSortPrefix($this->getOptions('dynamic_columns')));
             $config['group'][] = 'employee_number';
             $config['group'][] = 'date_stamp';
             $config['group'] = array_merge($config['columns'], (array) $setup_data['paychex_preview_advanced_job']['job_columns']);
             $config['group'][] = $setup_data['paychex_preview_advanced_job']['state_columns'];
             $config['sort'][] = array('employee_number' => 'asc');
             $config['sort'][] = array('date_stamp' => 'asc');
             //Debug::Arr($config, 'Job Detail Report Config: ', __FILE__, __LINE__, __METHOD__,10);
             //Get job data...
             $jar = TTNew('JobDetailReport');
             $jar->setAMFMessageID($this->getAMFMessageID());
             $jar->setUserObject($this->getUserObject());
             $jar->setPermissionObject($this->getPermissionObject());
             $jar->setConfig($config);
             $jar->setFilterConfig($this->getFilterConfig());
             $jar->setSortConfig($config['sort']);
             $jar->_getData();
             $jar->_preProcess();
             $jar->sort();
             $rows = $jar->data;
             //Debug::Arr($rows, 'Raw Rows: ', __FILE__, __LINE__, __METHOD__,10);
             //Need to get job data from job report instead of TimeSheet Summary report.
             if (!isset($setup_data['paychex_preview_advanced_job']['client_number'])) {
                 $setup_data['paychex_preview_advanced_job']['client_number'] = '0000';
             }
             $file_name = $setup_data['paychex_preview_advanced_job']['client_number'] . '_TA.txt';
             ksort($setup_data['paychex_preview_advanced_job']['columns']);
             $setup_data['paychex_preview_advanced_job']['columns'] = Misc::trimSortPrefix($setup_data['paychex_preview_advanced_job']['columns']);
             $data = NULL;
             foreach ($rows as $row) {
                 foreach ($setup_data['paychex_preview_advanced_job']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         $data .= str_pad($row['employee_number'], 6, ' ', STR_PAD_LEFT);
                         $data .= str_pad('', 31, ' ', STR_PAD_LEFT);
                         //Blank space.
                         if (isset($setup_data['paychex_preview_advanced_job']['job_columns']) and is_array($setup_data['paychex_preview_advanced_job']['job_columns'])) {
                             $job_column = array();
                             foreach ($setup_data['paychex_preview_advanced_job']['job_columns'] as $tmp_job_column) {
                                 $job_column[] = isset($row[$tmp_job_column]) ? $row[$tmp_job_column] : NULL;
                             }
                             $data .= str_pad(substr(implode('-', $job_column), 0, 12), 12, ' ', STR_PAD_LEFT);
                             unset($job_column);
                         } else {
                             $data .= str_pad('', 12, ' ', STR_PAD_LEFT);
                         }
                         $data .= str_pad('', 1, ' ', STR_PAD_LEFT);
                         //Shift identifier.
                         //Allow user to specify three digit hour codes to specify their own E/D codes. If codes are two digit, always use E.
                         if (strlen(trim($column_data['hour_code'])) < 3) {
                             $column_data['hour_code'] = 'E' . trim($column_data['hour_code']);
                         }
                         //Should start at col51
                         $data .= str_pad(substr(trim($column_data['hour_code']), 0, 3), 3, ' ', STR_PAD_RIGHT);
                         if (isset($setup_data['paychex_preview_advanced_job']['include_hourly_rate']) and $setup_data['paychex_preview_advanced_job']['include_hourly_rate'] == TRUE) {
                             $data .= str_pad(isset($row[$column_id . '_hourly_rate']) ? number_format($row[$column_id . '_hourly_rate'], 4, '.', '') : NULL, 9, 0, STR_PAD_LEFT);
                             //Override rate
                         } else {
                             $data .= str_pad('', 9, 0, STR_PAD_LEFT);
                             //Override rate
                         }
                         $data .= str_pad(TTDate::getTimeUnit($row[$column_id], 20), 8, 0, STR_PAD_LEFT);
                         //Break out time by day.
                         $data .= str_pad(TTDate::getYear($row['time_stamp']), 4, 0, STR_PAD_LEFT);
                         //Year, based on time_stamp epoch column
                         $data .= str_pad(TTDate::getMonth($row['time_stamp']), 2, 0, STR_PAD_LEFT);
                         //Month, based on time_stamp epoch column. Can be space padded.
                         $data .= str_pad(TTDate::getDayOfMonth($row['time_stamp']), 2, 0, STR_PAD_LEFT);
                         //Day, based on time_stamp epoch column. Can be space padded.
                         $data .= str_pad('', 4, ' ', STR_PAD_LEFT);
                         //Filler
                         $data .= str_pad('', 9, ' ', STR_PAD_LEFT);
                         //Amount. This can always be calculated from hours and hourly rate above though.
                         $data .= str_pad('', 13, ' ', STR_PAD_LEFT);
                         //Blank space
                         if (isset($setup_data['paychex_preview_advanced_job']['state_columns'])) {
                             $data .= str_pad(isset($row[$setup_data['paychex_preview_advanced_job']['state_columns']]) ? $row[$setup_data['paychex_preview_advanced_job']['state_columns']] : NULL, 2, ' ', STR_PAD_LEFT);
                             //State
                         }
                         $data .= "\n";
                     }
                 }
             }
             break;
         case 'paychex_preview':
             //Paychex Preview export format.
             //Add an advanced PayChex Preview format that supports rates perhaps?
             //http://kb.idb-sys.com/KnowledgebaseArticle10013.aspx
             if (!isset($setup_data['paychex_preview']['client_number'])) {
                 $setup_data['paychex_preview']['client_number'] = '0000';
             }
             $file_name = $setup_data['paychex_preview']['client_number'] . '_TA.txt';
             ksort($setup_data['paychex_preview']['columns']);
             $setup_data['paychex_preview']['columns'] = Misc::trimSortPrefix($setup_data['paychex_preview']['columns']);
             $data = NULL;
             foreach ($rows as $row) {
                 foreach ($setup_data['paychex_preview']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         $data .= str_pad($row['employee_number'], 6, ' ', STR_PAD_LEFT);
                         $data .= str_pad('E' . str_pad(trim($column_data['hour_code']), 2, ' ', STR_PAD_RIGHT), 47, ' ', STR_PAD_LEFT);
                         $data .= str_pad(str_pad(TTDate::getTimeUnit($row[$column_id], 20), 8, 0, STR_PAD_LEFT), 17, ' ', STR_PAD_LEFT) . "\n";
                     }
                 }
             }
             break;
         case 'paychex_online':
             //Paychex Online Payroll CSV
             ksort($setup_data['paychex_online']['columns']);
             $setup_data['paychex_online']['columns'] = Misc::trimSortPrefix($setup_data['paychex_online']['columns']);
             $earnings = array();
             //Find all the hours codes
             foreach ($setup_data['paychex_online']['columns'] as $column_id => $column_data) {
                 $hour_code = $column_data['hour_code'];
                 $earnings[] = $hour_code;
             }
             $export_column_map['employee_number'] = '';
             foreach ($earnings as $key => $value) {
                 $export_column_map[$value] = '';
             }
             $i = 0;
             foreach ($rows as $row) {
                 if ($i == 0) {
                     //Include header.
                     $tmp_row['employee_number'] = 'Employee Number';
                     foreach ($earnings as $key => $value) {
                         $tmp_row[$value] = $value . ' Hours';
                     }
                     $tmp_rows[] = $tmp_row;
                     unset($tmp_row);
                 }
                 //Combine all hours from the same code together.
                 foreach ($setup_data['paychex_online']['columns'] as $column_id => $column_data) {
                     $hour_code = trim($column_data['hour_code']);
                     if (isset($row[$column_id]) and $hour_code != '') {
                         if (!isset($tmp_hour_codes[$hour_code])) {
                             $tmp_hour_codes[$hour_code] = 0;
                         }
                         $tmp_hour_codes[$hour_code] = bcadd($tmp_hour_codes[$column_data['hour_code']], $row[$column_id]);
                         //Use seconds for math here.
                     }
                 }
                 if (isset($tmp_hour_codes)) {
                     $tmp_row['employee_number'] = $row['employee_number'];
                     foreach ($tmp_hour_codes as $hour_code => $hours) {
                         $tmp_row[$hour_code] = TTDate::getTimeUnit($hours, 20);
                     }
                     $tmp_rows[] = $tmp_row;
                     unset($tmp_hour_codes, $hour_code, $hours, $tmp_row);
                 }
                 $i++;
             }
             if (isset($tmp_rows)) {
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'millenium':
             //Millenium export format. Also used by Qqest.
             ksort($setup_data['millenium']['columns']);
             $setup_data['millenium']['columns'] = Misc::trimSortPrefix($setup_data['millenium']['columns']);
             $export_column_map = array('employee_number' => '', 'transaction_code' => '', 'hour_code' => '', 'hours' => '');
             foreach ($rows as $row) {
                 foreach ($setup_data['millenium']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         $tmp_rows[] = array('employee_number' => $row['employee_number'], 'transaction_code' => 'E', 'hour_code' => trim($column_data['hour_code']), 'hours' => TTDate::getTimeUnit($row[$column_id], 20));
                     }
                 }
             }
             if (isset($tmp_rows)) {
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'ceridian_insync':
             //Ceridian InSync export format. Needs to be .IMP to import? DOS line endings?
             if (!isset($setup_data['ceridian_insync']['employer_number']) or $setup_data['ceridian_insync']['employer_number'] == '') {
                 $setup_data['ceridian_insync']['employer_number'] = '0001';
             }
             $file_name = strtolower(trim($setup_data['export_type'])) . '_' . $setup_data['ceridian_insync']['employer_number'] . '_' . date('Y_m_d') . '.imp';
             ksort($setup_data['ceridian_insync']['columns']);
             $setup_data['ceridian_insync']['columns'] = Misc::trimSortPrefix($setup_data['ceridian_insync']['columns']);
             $export_column_map = array('employer_number' => '', 'import_type_id' => '', 'employee_number' => '', 'check_type' => '', 'hour_code' => '', 'value' => '', 'distribution' => '', 'rate' => '', 'premium' => '', 'day' => '', 'pay_period' => '');
             foreach ($rows as $row) {
                 foreach ($setup_data['ceridian_insync']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         $tmp_rows[] = array('employer_number' => $setup_data['ceridian_insync']['employer_number'], 'import_type_id' => 'COSTING', 'employee_number' => str_pad($row['employee_number'], 9, '0', STR_PAD_LEFT), 'check_type' => 'REG', 'hour_code' => trim($column_data['hour_code']), 'value' => TTDate::getTimeUnit($row[$column_id], 20), 'distribution' => NULL, 'rate' => NULL, 'premium' => NULL, 'day' => NULL, 'pay_period' => NULL);
                     }
                 }
             }
             if (isset($tmp_rows)) {
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE, "\r\n");
                 //Use DOS line endings only.
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'quickbooks':
             //Quickbooks Pro export format.
         //Quickbooks Pro export format.
         case 'quickbooks_advanced':
             //Quickbooks Pro export format.
             $file_name = 'payroll_export.iif';
             ksort($setup_data['quickbooks']['columns']);
             $setup_data['quickbooks']['columns'] = Misc::trimSortPrefix($setup_data['quickbooks']['columns']);
             //
             // Quickbooks header
             //
             /*
             	Company Create Time can be found by first running an Timer Activity export in QuickBooks and viewing the output.
             
             	PITEM field needs to be populated, as that is the PAYROLL ITEM in quickbooks. It can be the same as the ITEM field.
             	ITEM is the service item, can be mapped to department/task?
             	PROJ could be mapped to the default department/branch?
             */
             $data = "!TIMERHDR\tVER\tREL\tCOMPANYNAME\tIMPORTEDBEFORE\tFROMTIMER\tCOMPANYCREATETIME\n";
             $data .= "TIMERHDR\t8\t0\t" . trim($setup_data['quickbooks']['company_name']) . "\tN\tY\t" . trim($setup_data['quickbooks']['company_created_date']) . "\n";
             $data .= "!TIMEACT\tDATE\tJOB\tEMP\tITEM\tPITEM\tDURATION\tPROJ\tNOTE\tXFERTOPAYROLL\tBILLINGSTATUS\n";
             foreach ($rows as $row) {
                 foreach ($setup_data['quickbooks']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         //Make sure employee name is in format: LastName, FirstName MiddleInitial
                         $tmp_employee_name = $row['last_name'] . ', ' . $row['first_name'];
                         if (isset($row['middle_name']) and strlen($row['middle_name']) > 0) {
                             $tmp_employee_name .= ' ' . substr(trim($row['middle_name']), 0, 1);
                         }
                         $proj = NULL;
                         if (isset($row[$setup_data['quickbooks']['proj']])) {
                             $proj = $row[$setup_data['quickbooks']['proj']];
                         }
                         $item = NULL;
                         if (isset($row[$setup_data['quickbooks']['item']])) {
                             $item = $row[$setup_data['quickbooks']['item']];
                         }
                         $job = NULL;
                         if (isset($row[$setup_data['quickbooks']['job']])) {
                             $job = $row[$setup_data['quickbooks']['job']];
                         }
                         $data .= "TIMEACT\t" . date('n/j/y', $row['pay_period_end_date']) . "\t" . $job . "\t" . $tmp_employee_name . "\t" . $item . "\t" . trim($column_data['hour_code']) . "\t" . TTDate::getTimeUnit($row[$column_id], 10) . "\t" . $proj . "\t\tY\t0\n";
                         unset($tmp_employee_name);
                     }
                 }
             }
             break;
         case 'surepayroll':
             //SurePayroll Export format.
             ksort($setup_data['surepayroll']['columns']);
             $setup_data['surepayroll']['columns'] = Misc::trimSortPrefix($setup_data['surepayroll']['columns']);
             //
             //header
             //
             $data = 'TC' . "\n";
             $data .= '00001' . "\n";
             $export_column_map = array('pay_period_end_date' => 'Entry Date', 'employee_number' => 'Employee Number', 'last_name' => 'Last Name', 'first_name' => 'First Name', 'hour_code' => 'Payroll Code', 'value' => 'Hours');
             foreach ($rows as $row) {
                 foreach ($setup_data['surepayroll']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         //Debug::Arr($column_data,'Output2', __FILE__, __LINE__, __METHOD__,10);
                         $tmp_rows[] = array('pay_period_end_date' => date('m/d/Y', $row['pay_period_end_date']), 'employee_number' => $row['employee_number'], 'last_name' => $row['last_name'], 'first_name' => $row['first_name'], 'hour_code' => trim($column_data['hour_code']), 'value' => TTDate::getTimeUnit($row[$column_id], 20));
                     }
                 }
             }
             if (isset($tmp_rows)) {
                 $data .= Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE);
                 $data = str_replace('"', '', $data);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'chris21':
             //Chris21 Export format.
             //Columns required: Employee_number (2), Date (10), ADJUSTMENT_CODE (12), HOURS (13), SIGNED_HOURS(15)[?]
             //Use SIGNED_HOURS only, as it provides more space?
             //When using absences a leave start/end date must be specified other it won't be imported.
             ksort($setup_data['chris21']['columns']);
             $setup_data['chris21']['columns'] = Misc::trimSortPrefix($setup_data['chris21']['columns']);
             $data = '';
             foreach ($rows as $row) {
                 foreach ($setup_data['chris21']['columns'] as $column_id => $column_data) {
                     if (isset($row[$column_id]) and trim($column_data['hour_code']) != '') {
                         //Debug::Arr($column_data,'Output2: ID: '. $column_id, __FILE__, __LINE__, __METHOD__,10);
                         $data .= str_repeat(' ', 8);
                         //8 digits Blank
                         $data .= str_pad(substr($row['employee_number'], 0, 7), 7, ' ', STR_PAD_RIGHT);
                         //7 digits
                         $data .= str_repeat(' ', 11);
                         //14 digits Blank
                         $data .= date('dmy', $row['pay_period_end_date']);
                         //4 digits Date
                         $data .= str_repeat(' ', 4);
                         //4 digits Blank
                         $data .= str_pad(substr(trim($column_data['hour_code']), 0, 4), 4, ' ', STR_PAD_RIGHT);
                         //4 digits
                         $data .= '0000';
                         //4 digits HOURS field, always be 0, use SIGNED_HOURS instead.
                         $data .= str_repeat(' ', 4);
                         //CC_CODE: 4 digits Blank
                         $data .= str_pad(str_replace('.', '', TTDate::getTimeUnit($row[$column_id], 20)), 6, 0, STR_PAD_LEFT) . '+';
                         //SIGNED_HOURS: Hours without decimal padded to 6 digits, with '+' on the end.
                         //$data .= '+000000000'; 																	//Filler: Redefintion of SIGNED_HOURS.
                         $data .= '000000000';
                         //RATE: 9 chars
                         $data .= str_repeat(' ', 20);
                         //ACCT_NO: 20 chars
                         $data .= str_repeat(' ', 16);
                         //JOB_NUMBER: 16 chars
                         if (strpos($column_id, 'absence') !== FALSE) {
                             //Absence column, include LEAVE dates.
                             $data .= date('dmy', $row['pay_period_end_date']);
                             //LEAVE Start Date: 6 digits
                             $data .= date('dmy', $row['pay_period_end_date']);
                             //LEAVE End Date: 6 digits
                         }
                         $data .= "\n";
                     }
                 }
             }
             unset($tmp_rows, $column_id, $column_data, $rows, $row);
             break;
         case 'csv':
             //Generic CSV.
             $file_name = strtolower(trim($setup_data['export_type'])) . '_' . date('Y_m_d') . '.csv';
             //If this needs to be customized, they can just export any regular report. This could probably be removed completely except for the Hour Code mapping...
             ksort($setup_data['csv']['columns']);
             $setup_data['csv']['columns'] = Misc::trimSortPrefix($setup_data['csv']['columns']);
             $export_column_map = array('employee' => '', 'employee_number' => '', 'default_branch' => '', 'default_department' => '', 'pay_period' => '', 'branch_name' => '', 'department_name' => '', 'hour_code' => '', 'hours' => '');
             $i = 0;
             foreach ($rows as $row) {
                 if ($i == 0) {
                     //Include header.
                     $tmp_rows[] = array('employee' => 'Employee', 'employee_number' => 'Employee Number', 'default_branch' => 'Default Branch', 'default_department' => 'Default Department', 'pay_period' => 'Pay Period', 'branch_name' => 'Branch', 'department_name' => 'Department', 'hour_code' => 'Hours Code', 'hours' => 'Hours');
                 }
                 //Combine all hours from the same code together.
                 foreach ($setup_data['csv']['columns'] as $column_id => $column_data) {
                     $hour_code = trim($column_data['hour_code']);
                     if (isset($row[$column_id]) and $hour_code != '') {
                         if (!isset($tmp_hour_codes[$hour_code])) {
                             $tmp_hour_codes[$hour_code] = 0;
                         }
                         $tmp_hour_codes[$hour_code] = bcadd($tmp_hour_codes[$column_data['hour_code']], $row[$column_id]);
                         //Use seconds for math here.
                     }
                 }
                 if (isset($tmp_hour_codes)) {
                     foreach ($tmp_hour_codes as $hour_code => $hours) {
                         $tmp_rows[] = array('employee' => isset($row['full_name']) ? $row['full_name'] : NULL, 'employee_number' => isset($row['employee_number']) ? $row['employee_number'] : NULL, 'default_branch' => isset($row['default_branch']) ? $row['default_branch'] : NULL, 'default_department' => isset($row['default_department']) ? $row['default_department'] : NULL, 'pay_period' => isset($row['pay_period']['display']) ? $row['pay_period']['display'] : NULL, 'branch_name' => isset($row['branch_name']) ? $row['branch_name'] : NULL, 'department_name' => isset($row['department_name']) ? $row['department_name'] : NULL, 'hour_code' => $hour_code, 'hours' => TTDate::getTimeUnit($hours, 20));
                     }
                     unset($tmp_hour_codes, $hour_code, $hours);
                 }
                 $i++;
             }
             if (isset($tmp_rows)) {
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         case 'csv_advanced':
             //Generic CSV.
             unset($rows);
             //Ignore any existing timesheet summary data, we will be using our own job data below.
             //If this needs to be customized, they can just export any regular report. This could probably be removed completely except for the Hour Code mapping...
             if (!isset($setup_data['csv_advanced']['export_columns']) or isset($setup_data['csv_advanced']['export_columns']) and !is_array($setup_data['csv_advanced']['export_columns'])) {
                 $setup_data['csv_advanced']['export_columns'] = array('full_name', 'employee_number', 'default_branch', 'default_department', 'pay_period', 'date_stamp');
             }
             if (isset($setup_data['csv_advanced']['export_columns']) and is_array($setup_data['csv_advanced']['export_columns'])) {
                 //Debug::Arr($setup_data['csv_advanced']['export_columns'], 'Custom Columns defined: ', __FILE__, __LINE__, __METHOD__,10);
                 $config['columns'] = $config['group'] = $setup_data['csv_advanced']['export_columns'];
                 //Force sorting...
                 foreach ($setup_data['csv_advanced']['export_columns'] as $export_column) {
                     $config['sort'][] = array($export_column => 'asc');
                 }
                 $config['columns'] += array_keys(Misc::trimSortPrefix($this->getOptions('dynamic_columns')));
             }
             Debug::Arr($config, 'Job Detail Report Config: ', __FILE__, __LINE__, __METHOD__, 10);
             //Get job data...
             if (is_object($this->getUserObject()) and is_object($this->getUserObject()->getCompanyObject()) and $this->getUserObject()->getCompanyObject()->getProductEdition() >= TT_PRODUCT_CORPORATE) {
                 Debug::Text('Using Job Detail Report...', __FILE__, __LINE__, __METHOD__, 10);
                 $jar = TTNew('JobDetailReport');
             } else {
                 Debug::Text('Using TimeSheet Detail Report...', __FILE__, __LINE__, __METHOD__, 10);
                 $jar = TTNew('TimesheetDetailReport');
             }
             $jar->setAMFMessageID($this->getAMFMessageID());
             $jar->setUserObject($this->getUserObject());
             $jar->setPermissionObject($this->getPermissionObject());
             $jar->setConfig($config);
             $jar->setFilterConfig($this->getFilterConfig());
             $jar->setSortConfig($config['sort']);
             $jar->_getData();
             $jar->_preProcess();
             $jar->group();
             $jar->sort();
             $columns = Misc::trimSortPrefix($jar->getOptions('columns'));
             $rows = $jar->data;
             //Debug::Arr($rows, 'Raw Rows: ', __FILE__, __LINE__, __METHOD__,10);
             $file_name = strtolower(trim($setup_data['export_type'])) . '_' . date('Y_m_d') . '.csv';
             //If this needs to be customized, they can just export any regular report. This could probably be removed completely except for the Hour Code mapping...
             ksort($setup_data['csv_advanced']['columns']);
             $setup_data['csv_advanced']['columns'] = Misc::trimSortPrefix($setup_data['csv_advanced']['columns']);
             foreach ($setup_data['csv_advanced']['export_columns'] as $export_column) {
                 $export_column_map[$export_column] = '';
             }
             $export_column_map['hour_code'] = '';
             $export_column_map['hours'] = '';
             $i = 0;
             foreach ($rows as $row) {
                 if ($i == 0) {
                     //Include header.
                     foreach ($setup_data['csv_advanced']['export_columns'] as $export_column) {
                         Debug::Text('Header Row: ' . $export_column, __FILE__, __LINE__, __METHOD__, 10);
                         $tmp_rows[$i][$export_column] = isset($columns[$export_column]) ? $columns[$export_column] : NULL;
                     }
                     $tmp_rows[$i]['hour_code'] = 'Hours Code';
                     $tmp_rows[$i]['hours'] = 'Hours';
                     $i++;
                 }
                 //Combine all hours from the same code together.
                 foreach ($setup_data['csv_advanced']['columns'] as $column_id => $column_data) {
                     $hour_code = trim($column_data['hour_code']);
                     if (isset($row[$column_id]) and $hour_code != '') {
                         if (!isset($tmp_hour_codes[$hour_code])) {
                             $tmp_hour_codes[$hour_code] = 0;
                         }
                         $tmp_hour_codes[$hour_code] = bcadd($tmp_hour_codes[$column_data['hour_code']], $row[$column_id]);
                         //Use seconds for math here.
                     }
                 }
                 if (isset($tmp_hour_codes)) {
                     foreach ($tmp_hour_codes as $hour_code => $hours) {
                         foreach ($setup_data['csv_advanced']['export_columns'] as $export_column) {
                             $tmp_rows[$i][$export_column] = isset($row[$export_column]) ? isset($row[$export_column]['display']) ? $row[$export_column]['display'] : $row[$export_column] : NULL;
                             $tmp_rows[$i]['hour_code'] = $hour_code;
                             $tmp_rows[$i]['hours'] = TTDate::getTimeUnit($hours, 20);
                         }
                     }
                     unset($tmp_hour_codes, $hour_code, $hours);
                 }
                 $i++;
             }
             //Debug::Arr($tmp_rows, 'Tmp Rows: ', __FILE__, __LINE__, __METHOD__,10);
             if (isset($tmp_rows)) {
                 $data = Misc::Array2CSV($tmp_rows, $export_column_map, FALSE, FALSE);
             }
             unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
             break;
         default:
             //Send raw data so plugin can capture it and change it if needed.
             $data = $this->data;
             break;
     }
     //Debug::Arr($data, 'Export Data: ', __FILE__, __LINE__, __METHOD__,10);
     return array('file_name' => $file_name, 'mime_type' => $mime_type, 'data' => $data);
 }
Example #4
0
 static function inApplyFrequencyWindow($frequency_id, $start_date, $end_date, $frequency_criteria = array())
 {
     /*
     		 Frequency IDs:
     												20 => 'Annually',
     												25 => 'Quarterly',
     												30 => 'Monthly',
     												40 => 'Weekly',
     												100 => 'Specific Date', //Pay Period Dates, Hire Dates, Termination Dates, etc...
     */
     if (!isset($frequency_criteria['month'])) {
         $frequency_criteria['month'] = 0;
     }
     if (!isset($frequency_criteria['day_of_month'])) {
         $frequency_criteria['day_of_month'] = 0;
     }
     if (!isset($frequency_criteria['day_of_week'])) {
         $frequency_criteria['day_of_week'] = 0;
     }
     if (!isset($frequency_criteria['quarter_month'])) {
         $frequency_criteria['quarter_month'] = 0;
     }
     if (!isset($frequency_criteria['date'])) {
         $frequency_criteria['date'] = 0;
     }
     //Debug::Arr($frequency_criteria, 'Freq ID: '. $frequency_id .' Date: Start: '. TTDate::getDate('DATE+TIME', $start_date) .'('.$start_date.') End: '. TTDate::getDate('DATE+TIME', $end_date) .'('.$end_date.')', __FILE__, __LINE__, __METHOD__,10);
     $retval = FALSE;
     switch ($frequency_id) {
         case 20:
             //Annually
             $year_epoch1 = mktime(TTDate::getHour($start_date), TTDate::getMinute($start_date), TTDate::getSecond($start_date), $frequency_criteria['month'], $frequency_criteria['day_of_month'], TTDate::getYear($start_date));
             $year_epoch2 = mktime(TTDate::getHour($end_date), TTDate::getMinute($end_date), TTDate::getSecond($end_date), $frequency_criteria['month'], $frequency_criteria['day_of_month'], TTDate::getYear($end_date));
             //Debug::Text('Year1 EPOCH: '. TTDate::getDate('DATE+TIME', $year_epoch1) .'('. $year_epoch1 .')', __FILE__, __LINE__, __METHOD__,10);
             //Debug::Text('Year2 EPOCH: '. TTDate::getDate('DATE+TIME', $year_epoch2) .'('. $year_epoch2 .')', __FILE__, __LINE__, __METHOD__,10);
             if ($year_epoch1 >= $start_date and $year_epoch1 <= $end_date or $year_epoch2 >= $start_date and $year_epoch2 <= $end_date) {
                 $retval = TRUE;
             }
             break;
         case 25:
             //Quarterly
             //Handle quarterly like month, we just need to set the specific month from quarter_month.
             if (abs($end_date - $start_date) > 86400 * 93) {
                 //3 months
                 $retval = TRUE;
             } else {
                 for ($i = TTDate::getMiddleDayEpoch($start_date); $i <= TTDate::getMiddleDayEpoch($end_date); $i += 86400 * 1) {
                     if (self::getYearQuarterMonthNumber($i) == $frequency_criteria['quarter_month'] and $frequency_criteria['day_of_month'] == self::getDayOfMonth($i)) {
                         $retval = TRUE;
                         break;
                     }
                 }
             }
             break;
         case 30:
             //Monthly
             //Make sure if they specify the day of month to be 31, that is still works for months with 30, or 28-29 days, assuming 31 basically means the last day of the month
             if ($frequency_criteria['day_of_month'] > TTDate::getDaysInMonth($start_date) or $frequency_criteria['day_of_month'] > TTDate::getDaysInMonth($end_date)) {
                 $frequency_criteria['day_of_month'] = TTDate::getDaysInMonth($start_date);
                 if (TTDate::getDaysInMonth($end_date) < $frequency_criteria['day_of_month']) {
                     $frequency_criteria['day_of_month'] = TTDate::getDaysInMonth($end_date);
                 }
                 //Debug::Text('Apply frequency day of month exceeds days in this month, using last day of the month instead: '. $frequency_criteria['day_of_month'], __FILE__, __LINE__, __METHOD__,10);
             }
             $month_epoch1 = mktime(TTDate::getHour($start_date), TTDate::getMinute($start_date), TTDate::getSecond($start_date), TTDate::getMonth($start_date), $frequency_criteria['day_of_month'], TTDate::getYear($start_date));
             $month_epoch2 = mktime(TTDate::getHour($end_date), TTDate::getMinute($end_date), TTDate::getSecond($end_date), TTDate::getMonth($end_date), $frequency_criteria['day_of_month'], TTDate::getYear($end_date));
             //Debug::Text('Day of Month: '. $frequency_criteria['day_of_month'] .' Month EPOCH: '. TTDate::getDate('DATE+TIME', $month_epoch1) .' Current Month: '. TTDate::getMonth( $start_date ), __FILE__, __LINE__, __METHOD__,10);
             //Debug::Text('Month1 EPOCH: '. TTDate::getDate('DATE+TIME', $month_epoch1) .'('. $month_epoch1 .') Greater Than: '. TTDate::getDate('DATE+TIME', ($start_date)) .' Less Than: '.  TTDate::getDate('DATE+TIME', $end_date) .'('. $end_date .')', __FILE__, __LINE__, __METHOD__,10);
             //Debug::Text('Month2 EPOCH: '. TTDate::getDate('DATE+TIME', $month_epoch2) .'('. $month_epoch2 .') Greater Than: '. TTDate::getDate('DATE+TIME', ($start_date)) .' Less Than: '.  TTDate::getDate('DATE+TIME', $end_date) .'('. $end_date .')', __FILE__, __LINE__, __METHOD__,10);
             if ($month_epoch1 >= $start_date and $month_epoch1 <= $end_date or $month_epoch2 >= $start_date and $month_epoch2 <= $end_date) {
                 $retval = TRUE;
             }
             break;
         case 40:
             //Weekly
             $start_dow = self::getDayOfWeek($start_date);
             $end_dow = self::getDayOfWeek($end_date);
             if ($start_dow == $frequency_criteria['day_of_week'] or $end_dow == $frequency_criteria['day_of_week']) {
                 $retval = TRUE;
             } else {
                 if ($end_date - $start_date > 86400 * 7) {
                     $retval = TRUE;
                 } else {
                     for ($i = TTDate::getMiddleDayEpoch($start_date); $i <= TTDate::getMiddleDayEpoch($end_date); $i += 86400) {
                         if (self::getDayOfWeek($i) == $frequency_criteria['day_of_week']) {
                             $retval = TRUE;
                             break;
                         }
                     }
                 }
             }
             break;
         case 100:
             //Specific date
             Debug::Text('Specific Date: ' . TTDate::getDate('DATE+TIME', $frequency_criteria['date']), __FILE__, __LINE__, __METHOD__, 10);
             if ($frequency_criteria['date'] >= $start_date and $frequency_criteria['date'] <= $end_date) {
                 $retval = TRUE;
             }
             break;
     }
     Debug::Text('Retval ' . (int) $retval, __FILE__, __LINE__, __METHOD__, 10);
     return $retval;
 }
 function getNextDate($epoch = FALSE)
 {
     if ($epoch == '') {
         $epoch = TTDate::getTime();
     }
     if ($this->getSpecialDay() == 1 or $this->getSpecialDay() == 5) {
         Debug::text('Easter Sunday Date...', __FILE__, __LINE__, __METHOD__, 10);
         //Use easter_days() instead, as easter_date returns incorrect values for some timezones/years (2010 and US/Eastern on Windows)
         //$easter_epoch = easter_date(date('Y', $epoch));
         $easter_epoch = mktime(12, 0, 0, 3, 21 + easter_days(date('Y', $epoch)), date('Y', $epoch));
         //Fix "cross-year" bug.
         if ($easter_epoch < $epoch) {
             //$easter_epoch = easter_date(date('Y', $epoch)+1);
             $easter_epoch = mktime(12, 0, 0, 3, 21 + easter_days(date('Y', $epoch) + 1), date('Y', $epoch) + 1);
         }
         if ($this->getSpecialDay() == 1) {
             Debug::text('Good Friday Date...', __FILE__, __LINE__, __METHOD__, 10);
             //$holiday_epoch = mktime(12,0,0,date('n',$easter_epoch),date('j',$easter_epoch) - 2, date('Y', $easter_epoch));
             $holiday_epoch = $easter_epoch - 2 * 86400;
         } else {
             $holiday_epoch = $easter_epoch;
         }
     } else {
         if ($this->getType() == 10) {
             //Static
             Debug::text('Static Date...', __FILE__, __LINE__, __METHOD__, 10);
             //Static date
             $holiday_epoch = mktime(12, 0, 0, $this->getMonth(), $this->getDayOfMonth(), date('Y', $epoch));
             if ($holiday_epoch < $epoch) {
                 $holiday_epoch = mktime(12, 0, 0, $this->getMonth(), $this->getDayOfMonth(), date('Y', $epoch) + 1);
             }
         } elseif ($this->getType() == 20) {
             //Dynamic - Week Interval
             Debug::text('Dynamic - Week Interval... Current Month: ' . TTDate::getMonth($epoch) . ' Holiday Month: ' . $this->getMonth(), __FILE__, __LINE__, __METHOD__, 10);
             //Dynamic
             $start_month_epoch = TTDate::getBeginMonthEpoch($epoch);
             $end_month_epoch = mktime(12, 0, 0, $this->getMonth() + 1, 1, date('Y', $epoch) + 1);
             Debug::text('Start Epoch: ' . TTDate::getDate('DATE+TIME', $start_month_epoch) . ' End Epoch: ' . TTDate::getDate('DATE+TIME', $end_month_epoch), __FILE__, __LINE__, __METHOD__, 10);
             //Get all day of weeks in the month. Determine which is less or greater then day.
             $day_of_week_dates = array();
             $week_interval = 0;
             for ($i = $start_month_epoch; $i <= $end_month_epoch; $i += 86400) {
                 if (TTDate::getMonth($i) == $this->getMonth()) {
                     $day_of_week = TTDate::getDayOfWeek($i);
                     //Debug::text('I: '. $i .'('.TTDate::getDate('DATE+TIME', $i).') Current Day Of Week: '. $day_of_week .' Looking for Day Of Week: '. $this->getDayOfWeek(), __FILE__, __LINE__, __METHOD__, 10);
                     if ($day_of_week == abs($this->getDayOfWeek())) {
                         $day_of_week_dates[] = date('j', $i);
                         Debug::text('I: ' . $i . ' Day Of Month: ' . date('j', $i), __FILE__, __LINE__, __METHOD__, 10);
                         $week_interval++;
                     }
                     if ($week_interval >= $this->getWeekInterval()) {
                         $tmp_holiday_epoch = mktime(12, 0, 0, $this->getMonth(), $day_of_week_dates[$this->getWeekInterval() - 1], date('Y', $i));
                         //Make sure we keep processing until the holiday comes AFTER todays date.
                         if ($tmp_holiday_epoch > $epoch) {
                             break;
                         }
                     }
                 }
             }
             //Debug::Arr($day_of_week_dates, 'Week Dates Arr: ', __FILE__, __LINE__, __METHOD__, 10);
             //$holiday_epoch = mktime(12,0,0, $this->getMonth(), $day_of_week_dates[$this->getWeekInterval()-1], date('Y', $i));
             $holiday_epoch = $tmp_holiday_epoch;
         } elseif ($this->getType() == 30) {
             //Dynamic - Pivot Day
             Debug::text('Dynamic - Pivot Date...', __FILE__, __LINE__, __METHOD__, 10);
             //Dynamic
             if (TTDate::getMonth($epoch) > $this->getMonth()) {
                 $year_modifier = 1;
             } else {
                 $year_modifier = 0;
             }
             $start_epoch = mktime(12, 0, 0, $this->getMonth(), $this->getDayOfMonth(), date('Y', $epoch) + $year_modifier);
             $holiday_epoch = $start_epoch;
             $x = 0;
             $x_max = 100;
             if ($this->getPivotDayDirection() == 10 or $this->getPivotDayDirection() == 30) {
                 $direction_multiplier = -1;
             } else {
                 $direction_multiplier = 1;
             }
             $adjustment = 86400 * $direction_multiplier;
             // Adjust by 1 day before or after.
             if ($this->getPivotDayDirection() == 10 or $this->getPivotDayDirection() == 20) {
                 $holiday_epoch += $adjustment;
             }
             while ($this->getDayOfWeek() != TTDate::getDayOfWeek($holiday_epoch) and $x < $x_max) {
                 Debug::text('X: ' . $x . ' aTrying...' . TTDate::getDate('DATE+TIME', $holiday_epoch), __FILE__, __LINE__, __METHOD__, 10);
                 $holiday_epoch += $adjustment;
                 $x++;
             }
         }
     }
     Debug::text('Next Date for: ' . $this->getName() . ' is: ' . TTDate::getDate('DATE+TIME', $holiday_epoch), __FILE__, __LINE__, __METHOD__, 10);
     return $holiday_epoch;
 }
 function inApplyFrequencyWindow($current_epoch, $offset, $pay_period_end_date = NULL)
 {
     $retval = FALSE;
     switch ($this->getApplyFrequency()) {
         case 10:
             //Pay Period
             if ($pay_period_end_date == '') {
                 return FALSE;
             }
             if ($pay_period_end_date >= $current_epoch - $offset and $pay_period_end_date <= $current_epoch) {
                 $retval = TRUE;
             }
             break;
         case 20:
             //Year
             $year_epoch = mktime(0, 0, 0, $this->getApplyFrequencyMonth(), $this->getApplyFrequencyDayOfMonth(), TTDate::getYear($current_epoch));
             Debug::Text('Year EPOCH: ' . TTDate::getDate('DATE+TIME', $year_epoch), __FILE__, __LINE__, __METHOD__, 10);
             if ($year_epoch >= $current_epoch - $offset and $year_epoch <= $current_epoch) {
                 $retval = TRUE;
             }
             break;
         case 30:
             //Month
             $apply_frequency_day_of_month = $this->getApplyFrequencyDayOfMonth();
             //Make sure if they specify the day of month to be 31, that is still works for months with 30, or 28-29 days, assuming 31 basically means the last day of the month
             if ($apply_frequency_day_of_month > TTDate::getDaysInMonth($current_epoch)) {
                 $apply_frequency_day_of_month = TTDate::getDaysInMonth($current_epoch);
                 Debug::Text('Apply frequency day of month exceeds days in this month, using last day of the month instead: ' . $apply_frequency_day_of_month, __FILE__, __LINE__, __METHOD__, 10);
             }
             $month_epoch = mktime(0, 0, 0, TTDate::getMonth($current_epoch), $apply_frequency_day_of_month, TTDate::getYear($current_epoch));
             Debug::Text('Day of Month: ' . $this->getApplyFrequencyDayOfMonth() . ' Month EPOCH: ' . TTDate::getDate('DATE+TIME', $month_epoch) . ' Current Month: ' . TTDate::getMonth($current_epoch), __FILE__, __LINE__, __METHOD__, 10);
             Debug::Text('Month EPOCH: ' . TTDate::getDate('DATE+TIME', $month_epoch) . ' Greater Than: ' . TTDate::getDate('DATE+TIME', $current_epoch - $offset) . ' Less Than: ' . TTDate::getDate('DATE+TIME', $current_epoch), __FILE__, __LINE__, __METHOD__, 10);
             if ($month_epoch >= $current_epoch - $offset and $month_epoch <= $current_epoch) {
                 $retval = TRUE;
             }
             break;
         case 40:
             //Week
             Debug::Text('Current Day Of Week: ' . TTDate::getDayOfWeek($current_epoch - $offset), __FILE__, __LINE__, __METHOD__, 10);
             if ($this->getApplyFrequencyDayOfWeek() == TTDate::getDayOfWeek($current_epoch - $offset)) {
                 $retval = TRUE;
             }
             break;
     }
     Debug::Text('RetVal: ' . (int) $retval, __FILE__, __LINE__, __METHOD__, 10);
     return $retval;
 }
Example #7
0
     }
 default:
     $data['product_edition'] = Option::getByKey(getTTProductEdition(), $current_company->getOptions('product_edition'));
     //Get Employee counts for this month, and last month
     $month_of_year_arr = TTDate::getMonthOfYearArray();
     //This month
     if (isset($ytd) and $ytd == 1) {
         $begin_month_epoch = strtotime('-2 years');
     } else {
         $begin_month_epoch = TTDate::getBeginMonthEpoch(TTDate::getBeginMonthEpoch(time()) - 86400);
     }
     $cuclf = new CompanyUserCountListFactory();
     $cuclf->getMonthlyMinAvgMaxByCompanyIdAndStartDateAndEndDate($current_company->getId(), $begin_month_epoch, TTDate::getEndMonthEpoch(time()), NULL, NULL, NULL, array('date_stamp' => 'desc'));
     if ($cuclf->getRecordCount() > 0) {
         foreach ($cuclf as $cuc_obj) {
             $data['user_counts'][] = array('label' => $month_of_year_arr[TTDate::getMonth(TTDate::strtotime($cuc_obj->getColumn('date_stamp')))] . ' ' . TTDate::getYear(TTDate::strtotime($cuc_obj->getColumn('date_stamp'))), 'max_active_users' => $cuc_obj->getColumn('max_active_users'), 'max_inactive_users' => $cuc_obj->getColumn('max_inactive_users'), 'max_deleted_users' => $cuc_obj->getColumn('max_deleted_users'));
         }
     }
     $cjlf = new CronJobListFactory();
     $cjlf->getMostRecentlyRun();
     if ($cjlf->getRecordCount() > 0) {
         $cj_obj = $cjlf->getCurrent();
         $data['cron'] = array('last_run_date' => $cj_obj->getLastRunDate());
     }
     if (($current_company->getId() == 1 or isset($config_vars['other']['primary_company_id']) and $current_company->getId() == $config_vars['other']['primary_company_id']) and getTTProductEdition() > 10) {
         if (!isset($system_settings['license'])) {
             $system_settings['license'] = NULL;
         }
         //Set this so the license upload area at least shows up regardles of edition.
         $data['license_data'] = array();
         $license = new TTLicense();
Example #8
0
 /**
  * Get about data .
  *
  */
 function getAboutData($ytd = 0, $all_companies = FALSE)
 {
     global $config_vars;
     $clf = new CompanyListFactory();
     $sslf = new SystemSettingListFactory();
     $system_settings = $sslf->getAllArray();
     $clf->getByID(PRIMARY_COMPANY_ID);
     if ($clf->getRecordCount() == 1) {
         $primary_company = $clf->getCurrent();
     }
     $current_user = $this->getCurrentUserObject();
     if (isset($primary_company) and PRIMARY_COMPANY_ID == $current_user->getCompany()) {
         $current_company = $primary_company;
     } else {
         $current_company = $clf->getByID($current_user->getCompany())->getCurrent();
     }
     //$current_user_prefs = $current_user->getUserPreferenceObject();
     $data = $system_settings;
     if (isset($data['new_version']) and $data['new_version'] == TRUE) {
         $data['new_version'] = TRUE;
     } else {
         $data['new_version'] = FALSE;
     }
     $data['product_edition'] = Option::getByKey(DEPLOYMENT_ON_DEMAND == TRUE ? $current_company->getProductEdition() : getTTProductEdition(), $current_company->getOptions('product_edition'));
     $data['application_name'] = APPLICATION_NAME;
     $data['organization_url'] = ORGANIZATION_URL;
     //Get Employee counts for this month, and last month
     $month_of_year_arr = TTDate::getMonthOfYearArray();
     //This month
     if (isset($ytd) and $ytd == 1) {
         $begin_month_epoch = strtotime('-2 years');
     } else {
         $begin_month_epoch = TTDate::getBeginMonthEpoch(TTDate::getBeginMonthEpoch(time()) - 86400);
     }
     $cuclf = TTnew('CompanyUserCountListFactory');
     if (isset($config_vars['other']['primary_company_id']) and $current_company->getId() == $config_vars['other']['primary_company_id'] and $all_companies == TRUE) {
         $cuclf->getTotalMonthlyMinAvgMaxByCompanyStatusAndStartDateAndEndDate(10, $begin_month_epoch, TTDate::getEndMonthEpoch(time()), NULL, NULL, NULL, array('date_stamp' => 'desc'));
     } else {
         $cuclf->getMonthlyMinAvgMaxByCompanyIdAndStartDateAndEndDate($current_company->getId(), $begin_month_epoch, TTDate::getEndMonthEpoch(time()), NULL, NULL, NULL, array('date_stamp' => 'desc'));
     }
     Debug::Text('Company User Count Rows: ' . $cuclf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
     if ($cuclf->getRecordCount() > 0) {
         foreach ($cuclf as $cuc_obj) {
             $data['user_counts'][] = array('label' => $month_of_year_arr[TTDate::getMonth(TTDate::strtotime($cuc_obj->getColumn('date_stamp')))] . ' ' . TTDate::getYear(TTDate::strtotime($cuc_obj->getColumn('date_stamp'))), 'max_active_users' => $cuc_obj->getColumn('max_active_users'), 'max_inactive_users' => $cuc_obj->getColumn('max_inactive_users'), 'max_deleted_users' => $cuc_obj->getColumn('max_deleted_users'));
         }
     }
     if (isset($data['user_counts']) == FALSE) {
         $data['user_counts'] = array();
     }
     $cjlf = TTnew('CronJobListFactory');
     $cjlf->getMostRecentlyRun();
     if ($cjlf->getRecordCount() > 0) {
         $cj_obj = $cjlf->getCurrent();
         $data['cron'] = array('last_run_date' => $cj_obj->getLastRunDate() == FALSE ? TTi18n::getText('Never') : TTDate::getDate('DATE+TIME', $cj_obj->getLastRunDate()));
     }
     $data['show_license_data'] = FALSE;
     if ((DEPLOYMENT_ON_DEMAND == FALSE and $current_company->getId() == 1 or isset($config_vars['other']['primary_company_id']) and $current_company->getId() == $config_vars['other']['primary_company_id']) and getTTProductEdition() > 10) {
         if (!isset($system_settings['license'])) {
             $system_settings['license'] = NULL;
         }
         $data['show_license_data'] = TRUE;
         //Set this so the license upload area at least shows up regardles of edition.
         $data['license_data'] = array();
         $license = new TTLicense();
         $retval = $license->validateLicense($system_settings['license']);
         if ($retval == TRUE) {
             $data['license_data'] = array('organization_name' => $license->getOrganizationName(), 'major_version' => $license->getMajorVersion(), 'minor_version' => $license->getMinorVersion(), 'product_name' => $license->getProductName(), 'active_employee_licenses' => $license->getActiveEmployeeLicenses(), 'issue_date' => TTDate::getDate('DATE', $license->getIssueDate()), 'expire_date' => $license->getExpireDate(), 'expire_date_display' => TTDate::getDate('DATE', $license->getExpireDate()), 'registration_key' => $license->getRegistrationKey(), 'message' => $license->getFullErrorMessage($retval), 'retval' => $retval);
         }
     }
     //Debug::Arr($data, 'Data: ', __FILE__, __LINE__, __METHOD__,10);
     return $this->returnHandler($data);
 }