819 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			819 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/*********************************************************************************
 | 
						|
 *
 | 
						|
 * TimeTrex is a Workforce Management program developed by
 | 
						|
 * TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it under
 | 
						|
 * the terms of the GNU Affero General Public License version 3 as published by
 | 
						|
 * the Free Software Foundation with the addition of the following permission
 | 
						|
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 | 
						|
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
 | 
						|
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
						|
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 | 
						|
 * details.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Affero General Public License along
 | 
						|
 * with this program; if not, see http://www.gnu.org/licenses or write to the Free
 | 
						|
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
 * 02110-1301 USA.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
 | 
						|
 * #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * The interactive user interfaces in modified source and object code versions
 | 
						|
 * of this program must display Appropriate Legal Notices, as required under
 | 
						|
 * Section 5 of the GNU Affero General Public License version 3.
 | 
						|
 *
 | 
						|
 *
 | 
						|
 * In accordance with Section 7(b) of the GNU Affero General Public License
 | 
						|
 * version 3, these Appropriate Legal Notices must retain the display of the
 | 
						|
 * "Powered by TimeTrex" logo. If the display of the logo is not reasonably
 | 
						|
 * feasible for technical reasons, the Appropriate Legal Notices must display
 | 
						|
 * the words "Powered by TimeTrex".
 | 
						|
 *
 | 
						|
 ********************************************************************************/
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * @package API\Core
 | 
						|
 */
 | 
						|
class APITimeSheet extends APIFactory {
 | 
						|
	protected $main_class = false;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * APITimeSheet constructor.
 | 
						|
	 */
 | 
						|
	public function __construct() {
 | 
						|
		parent::__construct(); //Make sure parent constructor is always called.
 | 
						|
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get all necessary dates for building the TimeSheet in a single call, this is mainly as a performance optimization.
 | 
						|
	 * @param bool $base_date
 | 
						|
	 * @return array
 | 
						|
	 * @internal param array $data filter data
 | 
						|
	 */
 | 
						|
	function getTimeSheetDates( $base_date = null ) {
 | 
						|
		$epoch = TTDate::parseDateTime( $base_date );
 | 
						|
 | 
						|
 | 
						|
		if ( $epoch == '' || $epoch < 946728000 || $epoch > ( time() + ( 3650 * 86400 ) ) ) { //Make sure date is after 01-Jan-2000 and before 10 years in the future.
 | 
						|
			$epoch = TTDate::getTime();
 | 
						|
		}
 | 
						|
 | 
						|
		$start_date = TTDate::getBeginWeekEpoch( $epoch, $this->getCurrentUserPreferenceObject()->getStartWeekDay() );
 | 
						|
		$end_date = TTDate::getEndWeekEpoch( $epoch, $this->getCurrentUserPreferenceObject()->getStartWeekDay() );
 | 
						|
 | 
						|
		$retarr = [
 | 
						|
				'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 ),
 | 
						|
		];
 | 
						|
 | 
						|
		return $retarr;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get all data for displaying the timesheet.
 | 
						|
	 * @param string $user_id UUID
 | 
						|
	 * @param int $base_date  EPOCH
 | 
						|
	 * @param bool $data
 | 
						|
	 * @return array|bool
 | 
						|
	 */
 | 
						|
	function getTimeSheetData( $user_id, $base_date = null, $data = null ) {
 | 
						|
		if ( $user_id == '' || TTUUID::isUUID( $user_id ) == false ) {
 | 
						|
			//This isn't really permission issue, but in cases where the user can't see any employees timesheets, we want to display an error to them at least.
 | 
						|
			//return $this->returnHandler( FALSE );
 | 
						|
			return $this->getPermissionObject()->PermissionDenied();
 | 
						|
		}
 | 
						|
		$user_id = TTUUID::castUUID( $user_id );
 | 
						|
 | 
						|
		if ( $base_date == '' ) {
 | 
						|
			return $this->returnHandler( false );
 | 
						|
		}
 | 
						|
 | 
						|
		$profile_start = microtime( true );
 | 
						|
 | 
						|
		if ( !$this->getPermissionObject()->Check( 'punch', 'enabled' )
 | 
						|
				|| !( $this->getPermissionObject()->Check( 'punch', 'view' ) || $this->getPermissionObject()->Check( 'punch', 'view_child' ) || $this->getPermissionObject()->Check( 'punch', 'view_own' ) ) ) {
 | 
						|
			return $this->getPermissionObject()->PermissionDenied();
 | 
						|
		}
 | 
						|
 | 
						|
		//Get Permission Hierarchy Children first, as this can be used for viewing, or editing.
 | 
						|
		//Check for ===FALSE on permission_children_ids, as that means their are no children assigned to them and they don't have view all permissions.
 | 
						|
		$data['filter_data']['permission_children_ids'] = $this->getPermissionObject()->getPermissionChildren( 'punch', 'view' );
 | 
						|
		if ( $data['filter_data']['permission_children_ids'] === false || ( is_array( $data['filter_data']['permission_children_ids'] ) && !in_array( $user_id, $data['filter_data']['permission_children_ids'] ) ) ) {
 | 
						|
			return $this->getPermissionObject()->PermissionDenied();
 | 
						|
		}
 | 
						|
 | 
						|
		//
 | 
						|
		//Get timesheet start/end dates.
 | 
						|
		//
 | 
						|
		$timesheet_dates = $this->getTimesheetDates( $base_date );
 | 
						|
 | 
						|
		//Include all dates within the timesheet range.
 | 
						|
		$timesheet_dates['pay_period_date_map'] = []; //Add array containing date => pay_period_id pairs.
 | 
						|
 | 
						|
		//
 | 
						|
		//Get PayPeriod information
 | 
						|
		//
 | 
						|
		$pplf = TTnew( 'PayPeriodListFactory' ); /** @var PayPeriodListFactory $pplf */
 | 
						|
 | 
						|
		$pplf->StartTransaction();
 | 
						|
		//Make sure we all pay periods that fall within the start/end date, so we can properly display the timesheet range at the top.
 | 
						|
		$primary_pay_period_id = TTUUID::getZeroID();
 | 
						|
		$pay_period_ids = [];
 | 
						|
		$pplf->getByUserIdAndOverlapStartDateAndEndDate( $user_id, $timesheet_dates['start_date'], $timesheet_dates['end_date'] );
 | 
						|
		if ( $pplf->getRecordCount() > 0 ) {
 | 
						|
			foreach ( $pplf as $pp_obj ) {
 | 
						|
				$pay_period_ids[] = $pp_obj->getId();
 | 
						|
				if ( $pp_obj->getStartDate() <= $timesheet_dates['base_date'] && $pp_obj->getEndDate() >= $timesheet_dates['base_date'] ) {
 | 
						|
					$primary_pay_period_id = $pp_obj->getId();
 | 
						|
				}
 | 
						|
				$timesheet_dates['pay_period_date_map'] += (array)$pp_obj->getPayPeriodDates( $timesheet_dates['start_date'], $timesheet_dates['end_date'], true );
 | 
						|
			}
 | 
						|
			unset( $pp_obj );
 | 
						|
		}
 | 
						|
		//Debug::Text('Pay Periods: '. $pplf->getRecordCount() .' Primary Pay Period: '. $primary_pay_period_id, __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
		//Debug::Arr($timesheet_dates, 'TimeSheet Dates: ', __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
 | 
						|
		//
 | 
						|
		//Get punches
 | 
						|
		//
 | 
						|
		$punch_data = [];
 | 
						|
		$filter_data = $this->initializeFilterAndPager( [ 'filter_data' => [ 'start_date' => $timesheet_dates['start_date'], 'end_date' => $timesheet_dates['end_date'], 'user_id' => $user_id ] ], true );
 | 
						|
 | 
						|
		//Carry over timesheet filter options.
 | 
						|
		if ( isset( $data['filter_data']['branch_id'] ) ) {
 | 
						|
			$filter_data['filter_data']['branch_id'] = $data['filter_data']['branch_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['department_id'] ) ) {
 | 
						|
			$filter_data['filter_data']['department_id'] = $data['filter_data']['department_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['job_id'] ) ) {
 | 
						|
			$filter_data['filter_data']['job_id'] = $data['filter_data']['job_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['job_item_id'] ) ) {
 | 
						|
			$filter_data['filter_data']['job_item_id'] = $data['filter_data']['job_item_id'];
 | 
						|
		}
 | 
						|
 | 
						|
		$plf = TTnew( 'PunchListFactory' ); /** @var PunchListFactory $plf */
 | 
						|
		$plf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), $filter_data['filter_data'], $filter_data['filter_items_per_page'], $filter_data['filter_page'], null, [ 'b.pay_period_id' => 'asc', 'b.user_id' => 'asc', 'a.time_stamp' => 'asc', 'a.punch_control_id' => 'asc', 'a.status_id' => 'asc' ] ); //Order is critical to the timesheet layout.
 | 
						|
		Debug::Text( 'Punch Record Count: ' . $plf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
		if ( $plf->getRecordCount() > 0 ) {
 | 
						|
			//Reduces data transfer by about half.
 | 
						|
			$punch_columns = [
 | 
						|
					'id'                => true,
 | 
						|
					'user_id'           => true,
 | 
						|
					'transfer'          => true,
 | 
						|
					'type_id'           => true,
 | 
						|
					'type'              => true,
 | 
						|
					'status_id'         => true,
 | 
						|
					'status'            => true,
 | 
						|
					'time_stamp'        => true,
 | 
						|
					'raw_time_stamp'    => true,
 | 
						|
					'punch_date'        => true,
 | 
						|
					'punch_time'        => true,
 | 
						|
					'actual_time_stamp'	=> true, //Required for hiding duplicates when there is a pending punch from job queue.
 | 
						|
					'punch_control_id'  => true,
 | 
						|
					'longitude'         => true,
 | 
						|
					'latitude'          => true,
 | 
						|
					'position_accuracy' => true,
 | 
						|
					'date_stamp'        => true,
 | 
						|
					'pay_period_id'     => true,
 | 
						|
					'note'              => true,
 | 
						|
					'tainted'           => true,
 | 
						|
					'has_image'         => true,
 | 
						|
					'branch_id'         => true,
 | 
						|
					'department_id'     => true,
 | 
						|
					'job_id'            => true,
 | 
						|
					'job_item_id'       => true,
 | 
						|
			];
 | 
						|
 | 
						|
			foreach ( $plf as $p_obj ) {
 | 
						|
				//$punch_data[] = $p_obj->getObjectAsArray( NULL, $data['filter_data']['permission_children_ids'] );
 | 
						|
				//Don't need to pass permission_children_ids, as Flex uses is_owner/is_child from the timesheet user record instead, not the punch record.
 | 
						|
				$punch_data[] = $p_obj->getObjectAsArray( $punch_columns );
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		$meal_and_break_total_data = PunchFactory::calcMealAndBreakTotalTime( $punch_data );
 | 
						|
		if ( $meal_and_break_total_data === false ) {
 | 
						|
			$meal_and_break_total_data = [];
 | 
						|
		}
 | 
						|
 | 
						|
		//Get Wage Permission Hierarchy Children first, as this can be used for viewing, or editing.
 | 
						|
		$wage_permission_children_ids = $this->getPermissionObject()->getPermissionChildren( 'wage', 'view' );
 | 
						|
 | 
						|
		//
 | 
						|
		//Get total time for day/pay period
 | 
						|
		//
 | 
						|
		$user_date_total_data = [];
 | 
						|
		$absence_user_date_total_data = [];
 | 
						|
		$udt_filter_data = $this->initializeFilterAndPager( [ 'filter_data' => [ 'start_date' => $timesheet_dates['start_date'], 'end_date' => $timesheet_dates['end_date'], 'user_id' => $user_id ] ], true );
 | 
						|
 | 
						|
		//Carry over timesheet filter options.
 | 
						|
		if ( isset( $data['filter_data']['branch_id'] ) ) {
 | 
						|
			$udt_filter_data['filter_data']['branch_id'] = $data['filter_data']['branch_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['department_id'] ) ) {
 | 
						|
			$udt_filter_data['filter_data']['department_id'] = $data['filter_data']['department_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['job_id'] ) ) {
 | 
						|
			$udt_filter_data['filter_data']['job_id'] = $data['filter_data']['job_id'];
 | 
						|
		}
 | 
						|
		if ( isset( $data['filter_data']['job_item_id'] ) ) {
 | 
						|
			$udt_filter_data['filter_data']['job_item_id'] = $data['filter_data']['job_item_id'];
 | 
						|
		}
 | 
						|
 | 
						|
		$udtlf = TTnew( 'UserDateTotalListFactory' ); /** @var UserDateTotalListFactory $udtlf */
 | 
						|
		$udtlf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), $udt_filter_data['filter_data'], $udt_filter_data['filter_items_per_page'], $udt_filter_data['filter_page'], null, $udt_filter_data['filter_sort'] );
 | 
						|
		Debug::Text( 'User Date Total Record Count: ' . $udtlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
		if ( $udtlf->getRecordCount() > 0 ) {
 | 
						|
			//Specifying the columns is about a 30% speed up for large timesheets.
 | 
						|
			$udt_columns = [
 | 
						|
					'id'         => true,
 | 
						|
					'user_id'    => true,
 | 
						|
					'date_stamp' => true,
 | 
						|
 | 
						|
					//'status_id' => TRUE,
 | 
						|
					//'type_id' => TRUE,
 | 
						|
 | 
						|
					'object_type_id' => true,
 | 
						|
					'src_object_id'  => true,
 | 
						|
					'pay_code_id'    => true,
 | 
						|
					'policy_name'    => true,
 | 
						|
					'name'           => true,
 | 
						|
 | 
						|
					'branch_id'     => true,
 | 
						|
					'branch'        => true,
 | 
						|
					'department_id' => true,
 | 
						|
					'department'    => true,
 | 
						|
					'job_id'        => true,
 | 
						|
					'job'           => true,
 | 
						|
					'job_item_id'   => true,
 | 
						|
					'job_item'      => true,
 | 
						|
 | 
						|
					'total_time' => true,
 | 
						|
 | 
						|
					'pay_period_id' => true,
 | 
						|
 | 
						|
					'override' => true,
 | 
						|
					'note'     => true,
 | 
						|
			];
 | 
						|
 | 
						|
			if ( $this->getPermissionObject()->isPermissionChild( $user_id, $wage_permission_children_ids ) ) {
 | 
						|
				$udt_columns['total_time_amount'] = true;
 | 
						|
				$udt_columns['hourly_rate'] = true;
 | 
						|
			}
 | 
						|
 | 
						|
			foreach ( $udtlf as $udt_obj ) {
 | 
						|
				//Don't need to pass permission_children_ids, as Flex uses is_owner/is_child from the timesheet user record instead, not the punch record.
 | 
						|
				//$user_date_total = $udt_obj->getObjectAsArray( NULL, $data['filter_data']['permission_children_ids'] );
 | 
						|
				$user_date_total = $udt_obj->getObjectAsArray( $udt_columns );
 | 
						|
				$user_date_total_data[] = $user_date_total;
 | 
						|
 | 
						|
				//Extract just absence records so we can send those to the user, rather than all UDT rows as only absences are used.
 | 
						|
				if ( $user_date_total['object_type_id'] == 50 ) {
 | 
						|
					$absence_user_date_total_data[] = $user_date_total;
 | 
						|
				}
 | 
						|
 | 
						|
				//Get all pay periods that have total time assigned to them.
 | 
						|
				$timesheet_dates['pay_period_date_map'][$user_date_total['date_stamp']] = $pay_period_ids[] = $user_date_total['pay_period_id'];
 | 
						|
 | 
						|
				//Adjust primary pay period if the pay period schedules were changed mid-way through perhaps.
 | 
						|
				if ( $timesheet_dates['base_display_date'] == $user_date_total['date_stamp'] && $timesheet_dates['pay_period_date_map'][$user_date_total['date_stamp']] != $primary_pay_period_id ) {
 | 
						|
					$primary_pay_period_id = $user_date_total['pay_period_id'];
 | 
						|
					Debug::Text( 'Changing primary pay period to: ' . $primary_pay_period_id, __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
				}
 | 
						|
			}
 | 
						|
			unset( $user_date_total );
 | 
						|
		}
 | 
						|
		//Debug::Arr( $timesheet_dates['pay_period_date_map'], 'Date/Pay Period IDs. Primary Pay Period ID: ' . $primary_pay_period_id, __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
 | 
						|
		$accumulated_user_date_total_data = UserDateTotalFactory::calcAccumulatedTime( $user_date_total_data );
 | 
						|
		if ( $accumulated_user_date_total_data === false ) {
 | 
						|
			$accumulated_user_date_total_data = [];
 | 
						|
		}
 | 
						|
		unset( $user_date_total_data );
 | 
						|
 | 
						|
		//Get data for all pay periods
 | 
						|
		$pay_period_data = [];
 | 
						|
		$pplf->getByIDList( $pay_period_ids );
 | 
						|
		if ( $pplf->getRecordCount() > 0 ) {
 | 
						|
			$pp_columns = [
 | 
						|
					'id'               => true,
 | 
						|
					'status_id'        => true,
 | 
						|
					//'status' => TRUE,
 | 
						|
					'type_id'          => true,
 | 
						|
					//'type' => TRUE,
 | 
						|
					//'pay_period_schedule_id' => TRUE,
 | 
						|
					'start_date'       => true,
 | 
						|
					'end_date'         => true,
 | 
						|
					'transaction_date' => true,
 | 
						|
			];
 | 
						|
 | 
						|
			foreach ( $pplf as $pp_obj ) {
 | 
						|
				$pay_period_data[$pp_obj->getId()] = $pp_obj->getObjectAsArray( $pp_columns );
 | 
						|
				$pay_period_data[$pp_obj->getId()]['timesheet_verify_type_id'] = $pp_obj->getTimeSheetVerifyType();
 | 
						|
				$pay_period_data[$pp_obj->getId()]['start_date_epoch'] = $pp_obj->getStartDate();
 | 
						|
				$pay_period_data[$pp_obj->getId()]['end_date_epoch'] = $pp_obj->getEndDate();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		unset( $pp_obj );
 | 
						|
 | 
						|
		//Fill in payperiod gaps in timesheet primarily for migrating from one schedule to another or for new hires in middle of a pay period
 | 
						|
		$calendar_dates = TTDate::getCalendarArray( $timesheet_dates['start_date'], $timesheet_dates['end_date'], 0, false );
 | 
						|
		foreach ( $calendar_dates as $tmp_date ) {
 | 
						|
			if ( !isset( $timesheet_dates['pay_period_date_map'][TTDate::getDate( 'DATE', $tmp_date['epoch'] )] ) ) {
 | 
						|
				foreach ( $pay_period_data as $tmp_pp_data ) {
 | 
						|
					if ( $tmp_date['epoch'] >= $tmp_pp_data['start_date_epoch'] && $tmp_date['epoch'] <= $tmp_pp_data['end_date_epoch'] ) {
 | 
						|
						$timesheet_dates['pay_period_date_map'][TTDate::getDate( 'DATE', $tmp_date['epoch'] )] = $tmp_pp_data['id'];
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		ksort( $timesheet_dates['pay_period_date_map'] );
 | 
						|
		unset( $calendar_dates, $tmp_date, $tmp_pp_data );
 | 
						|
 | 
						|
		$pp_user_date_total_data = [];
 | 
						|
		$pay_period_accumulated_user_date_total_data = [];
 | 
						|
		if ( isset( $primary_pay_period_id ) && TTUUID::isUUID( $primary_pay_period_id ) && $primary_pay_period_id != TTUUID::getZeroID() && $primary_pay_period_id != TTUUID::getNotExistID() ) {
 | 
						|
			$pp_udt_filter_data = $this->initializeFilterAndPager( [ 'filter_data' => [ 'pay_period_id' => $primary_pay_period_id, 'user_id' => $user_id ] ], true );
 | 
						|
 | 
						|
			//Carry over timesheet filter options.
 | 
						|
			if ( isset( $data['filter_data']['branch_id'] ) ) {
 | 
						|
				$pp_udt_filter_data['filter_data']['branch_id'] = $data['filter_data']['branch_id'];
 | 
						|
			}
 | 
						|
			if ( isset( $data['filter_data']['department_id'] ) ) {
 | 
						|
				$pp_udt_filter_data['filter_data']['department_id'] = $data['filter_data']['department_id'];
 | 
						|
			}
 | 
						|
			if ( isset( $data['filter_data']['job_id'] ) ) {
 | 
						|
				$pp_udt_filter_data['filter_data']['job_id'] = $data['filter_data']['job_id'];
 | 
						|
			}
 | 
						|
			if ( isset( $data['filter_data']['job_item_id'] ) ) {
 | 
						|
				$pp_udt_filter_data['filter_data']['job_item_id'] = $data['filter_data']['job_item_id'];
 | 
						|
			}
 | 
						|
 | 
						|
			$udtlf = TTnew( 'UserDateTotalListFactory' ); /** @var UserDateTotalListFactory $udtlf */
 | 
						|
			$udtlf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), $pp_udt_filter_data['filter_data'], $pp_udt_filter_data['filter_items_per_page'], $pp_udt_filter_data['filter_page'], null, $pp_udt_filter_data['filter_sort'] );
 | 
						|
			Debug::Text( 'PP User Date Total Record Count: ' . $udtlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
			if ( $udtlf->getRecordCount() > 0 ) {
 | 
						|
				//Specifying the columns is about a 30% speed up for large timesheets.
 | 
						|
				//This is only needed for calcAccumulatedTime().
 | 
						|
				$udt_columns = [
 | 
						|
						'object_type_id' => true,
 | 
						|
						'date_stamp'     => true,
 | 
						|
						'name'           => true,
 | 
						|
						'pay_code_id'    => true,
 | 
						|
						'total_time'     => true,
 | 
						|
 | 
						|
						'branch_id'     => true,
 | 
						|
						'branch'        => true,
 | 
						|
						'department_id' => true,
 | 
						|
						'department'    => true,
 | 
						|
						'job_id'        => true,
 | 
						|
						'job'           => true,
 | 
						|
						'job_item_id'   => true,
 | 
						|
						'job_item'      => true,
 | 
						|
				];
 | 
						|
 | 
						|
				if ( $this->getPermissionObject()->isPermissionChild( $user_id, $wage_permission_children_ids ) ) {
 | 
						|
					$udt_columns['total_time_amount'] = true;
 | 
						|
					$udt_columns['hourly_rate'] = true;
 | 
						|
				}
 | 
						|
 | 
						|
				foreach ( $udtlf as $udt_obj ) {
 | 
						|
					$pp_user_date_total_data[] = $udt_obj->getObjectAsArray( $udt_columns );
 | 
						|
				}
 | 
						|
 | 
						|
				$pay_period_accumulated_user_date_total_data = UserDateTotalFactory::calcAccumulatedTime( $pp_user_date_total_data, false );
 | 
						|
				if ( isset( $pay_period_accumulated_user_date_total_data['total'] ) ) {
 | 
						|
					$pay_period_accumulated_user_date_total_data = $pay_period_accumulated_user_date_total_data['total'];
 | 
						|
				} else {
 | 
						|
					$pay_period_accumulated_user_date_total_data = [];
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		unset( $pp_user_date_total_data );
 | 
						|
 | 
						|
 | 
						|
		//
 | 
						|
		//Get Exception data, use the same filter data as punches.
 | 
						|
		//
 | 
						|
		$exception_data = [];
 | 
						|
 | 
						|
		$elf = TTnew( 'ExceptionListFactory' ); /** @var ExceptionListFactory $elf */
 | 
						|
		$elf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), $filter_data['filter_data'], $filter_data['filter_items_per_page'], $filter_data['filter_page'], null, $filter_data['filter_sort'] );
 | 
						|
		Debug::Text( 'Exception Record Count: ' . $elf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
		if ( $elf->getRecordCount() > 0 ) {
 | 
						|
			//Reduces data transfer.
 | 
						|
			$exception_columns = [
 | 
						|
					'id'                         => true,
 | 
						|
					'date_stamp'                 => true,
 | 
						|
					'exception_policy_id'        => true,
 | 
						|
					'punch_control_id'           => true,
 | 
						|
					'punch_id'                   => true,
 | 
						|
					'type_id'                    => true,
 | 
						|
					'type'                       => true,
 | 
						|
					'severity_id'                => true,
 | 
						|
					'severity'                   => true,
 | 
						|
					'exception_color'            => true,
 | 
						|
					'exception_background_color' => true,
 | 
						|
					'exception_policy_type_id'   => true,
 | 
						|
					'exception_policy_type'      => true,
 | 
						|
					'pay_period_id'              => true,
 | 
						|
			];
 | 
						|
 | 
						|
			foreach ( $elf as $e_obj ) {
 | 
						|
				$exception_data[] = $e_obj->getObjectAsArray( $exception_columns );
 | 
						|
			}
 | 
						|
		}
 | 
						|
		unset( $elf, $e_obj, $exception_columns );
 | 
						|
 | 
						|
		//
 | 
						|
		//Get request data, so authorized/pending can be shown in a request row for each day.
 | 
						|
		//If there are two requests for both authorized and pending, the pending is displayed.
 | 
						|
		//
 | 
						|
		$request_data = [];
 | 
						|
 | 
						|
		$rlf = TTnew( 'RequestListFactory' ); /** @var RequestListFactory $rlf */
 | 
						|
		$rlf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), $filter_data['filter_data'], $filter_data['filter_items_per_page'], $filter_data['filter_page'], null, $filter_data['filter_sort'] );
 | 
						|
		Debug::Text( 'Request Record Count: ' . $rlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
		if ( $rlf->getRecordCount() > 0 ) {
 | 
						|
			$request_columns = [
 | 
						|
					'id'         => true,
 | 
						|
					'user_id'    => true,
 | 
						|
					'type_id'    => true,
 | 
						|
					'status_id'  => true,
 | 
						|
					'status'     => true,
 | 
						|
					'date_stamp' => true,
 | 
						|
					'authorized' => true,
 | 
						|
			];
 | 
						|
 | 
						|
			foreach ( $rlf as $r_obj ) {
 | 
						|
				$request_data[] = $r_obj->getObjectAsArray( $request_columns );
 | 
						|
			}
 | 
						|
		}
 | 
						|
		unset( $rlf, $r_obj, $request_columns );
 | 
						|
 | 
						|
		//
 | 
						|
		//Get timesheet verification information.
 | 
						|
		//
 | 
						|
		$timesheet_verify_data = [];
 | 
						|
		if ( isset( $primary_pay_period_id ) && TTUUID::isUUID( $primary_pay_period_id ) && $primary_pay_period_id != TTUUID::getZeroID() && $primary_pay_period_id != TTUUID::getNotExistID() ) {
 | 
						|
			$pptsvlf = TTnew( 'PayPeriodTimeSheetVerifyListFactory' ); /** @var PayPeriodTimeSheetVerifyListFactory $pptsvlf */
 | 
						|
			$pptsvlf->getByPayPeriodIdAndUserId( $primary_pay_period_id, $user_id );
 | 
						|
 | 
						|
			if ( $pptsvlf->getRecordCount() > 0 ) {
 | 
						|
				$pptsv_obj = $pptsvlf->getCurrent();
 | 
						|
				$pptsv_obj->setCurrentUser( $this->getCurrentUserObject()->getId() );
 | 
						|
			} else {
 | 
						|
				$pptsv_obj = $pptsvlf;
 | 
						|
				$pptsv_obj->setCurrentUser( $this->getCurrentUserObject()->getId() );
 | 
						|
				$pptsv_obj->setUser( $user_id );
 | 
						|
				$pptsv_obj->setPayPeriod( $primary_pay_period_id );
 | 
						|
				//$pptsv_obj->setStatus( 45 ); //Pending Verification
 | 
						|
			}
 | 
						|
 | 
						|
			$verification_window_dates = $pptsv_obj->getVerificationWindowDates();
 | 
						|
			if ( is_array( $verification_window_dates ) ) {
 | 
						|
				$verification_window_dates['start'] = TTDate::getAPIDate( 'DATE', $verification_window_dates['start'] );
 | 
						|
				$verification_window_dates['end'] = TTDate::getAPIDate( 'DATE', $verification_window_dates['end'] );
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			$timesheet_verify_data = [
 | 
						|
					'id'                                       => $pptsv_obj->getId(),
 | 
						|
					'user_verified'                            => $pptsv_obj->getUserVerified(),
 | 
						|
					'user_verified_date'                       => $pptsv_obj->getUserVerifiedDate(),
 | 
						|
					'status_id'                                => $pptsv_obj->getStatus(),
 | 
						|
					'status'                                   => Option::getByKey( $pptsv_obj->getStatus(), $pptsv_obj->getOptions( 'status' ) ),
 | 
						|
					'pay_period_id'                            => $pptsv_obj->getPayPeriod(),
 | 
						|
					'user_id'                                  => $pptsv_obj->getUser(),
 | 
						|
					'authorized'                               => $pptsv_obj->getAuthorized(),
 | 
						|
					'is_hierarchy_superior'                    => $pptsv_obj->isHierarchySuperior(),
 | 
						|
					'display_verify_button'                    => $pptsv_obj->displayVerifyButton(),
 | 
						|
					'verification_box_color'                   => $pptsv_obj->getVerificationBoxColor(),
 | 
						|
					'verification_status_display'              => $pptsv_obj->getVerificationStatusDisplay(),
 | 
						|
					'previous_pay_period_verification_display' => $pptsv_obj->displayPreviousPayPeriodVerificationNotice(),
 | 
						|
					'verification_confirmation_message'        => $pptsv_obj->getVerificationConfirmationMessage(),
 | 
						|
					'verification_window_dates'                => $verification_window_dates,
 | 
						|
 | 
						|
					'created_date' => $pptsv_obj->getCreatedDate(),
 | 
						|
					'created_by'   => $pptsv_obj->getCreatedBy(),
 | 
						|
					'updated_date' => $pptsv_obj->getUpdatedDate(),
 | 
						|
					'updated_by'   => $pptsv_obj->getUpdatedBy(),
 | 
						|
					//'deleted_date' => $pptsv_obj->getDeletedDate(),
 | 
						|
					//'deleted_by' => $pptsv_obj->getDeletedBy()
 | 
						|
			];
 | 
						|
			unset( $pptsvlf, $pptsv_obj, $verification_window_dates );
 | 
						|
 | 
						|
			if ( isset( $pay_period_data[$primary_pay_period_id] ) ) {
 | 
						|
				$timesheet_verify_data['pay_period_verify_type_id'] = $pay_period_data[$primary_pay_period_id]['timesheet_verify_type_id'];
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		//
 | 
						|
		//Get holiday data.
 | 
						|
		//
 | 
						|
		$holiday_data = [];
 | 
						|
		$hlf = TTnew( 'HolidayListFactory' ); /** @var HolidayListFactory $hlf */
 | 
						|
		$hlf->getAPISearchByCompanyIdAndArrayCriteria( $this->getCurrentCompanyObject()->getId(), [ 'start_date' => $timesheet_dates['start_date'], 'end_date' => $timesheet_dates['end_date'], 'user_id' => $user_id ], $filter_data['filter_items_per_page'], $filter_data['filter_page'], null, $filter_data['filter_sort'] );
 | 
						|
		Debug::Text( 'Holiday Record Count: ' . $hlf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
		if ( $hlf->getRecordCount() > 0 ) {
 | 
						|
			$holiday_columns = [
 | 
						|
					'id'                => true,
 | 
						|
					'holiday_policy_id' => true,
 | 
						|
					'date_stamp'        => true,
 | 
						|
					'name'              => true,
 | 
						|
			];
 | 
						|
 | 
						|
			foreach ( $hlf as $h_obj ) {
 | 
						|
				$holiday_data[] = $h_obj->getObjectAsArray( $holiday_columns );
 | 
						|
			}
 | 
						|
		}
 | 
						|
		unset( $hlf, $h_obj, $holiday_columns );
 | 
						|
 | 
						|
		$pplf->CommitTransaction();
 | 
						|
 | 
						|
		$retarr = [
 | 
						|
				'timesheet_dates' => $timesheet_dates,
 | 
						|
				'pay_period_data' => $pay_period_data,
 | 
						|
 | 
						|
				'punch_data' => $punch_data,
 | 
						|
 | 
						|
				'holiday_data' => $holiday_data,
 | 
						|
 | 
						|
				'user_date_total_data'                        => $absence_user_date_total_data, //Currently just absence records, as those are the only ones used.
 | 
						|
				'accumulated_user_date_total_data'            => $accumulated_user_date_total_data,
 | 
						|
				'pay_period_accumulated_user_date_total_data' => $pay_period_accumulated_user_date_total_data,
 | 
						|
				'meal_and_break_total_data'                   => $meal_and_break_total_data,
 | 
						|
 | 
						|
				'exception_data'        => $exception_data,
 | 
						|
				'request_data'          => $request_data,
 | 
						|
				'timesheet_verify_data' => $timesheet_verify_data,
 | 
						|
		];
 | 
						|
 | 
						|
		//Debug::Arr($retarr, 'TimeSheet Data: ', __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
		Debug::Text( 'TimeSheet Data: User ID:' . $user_id . ' Base Date: ' . $base_date . ' in: ' . ( microtime( true ) - $profile_start ) . 's', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
 | 
						|
		return $this->returnHandler( $retarr );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Get all data for displaying the timesheet.
 | 
						|
	 * @param string $user_id UUID
 | 
						|
	 * @param int $base_date  EPOCH
 | 
						|
	 * @return array
 | 
						|
	 */
 | 
						|
	function getTimeSheetTotalData( $user_id, $base_date = null ) {
 | 
						|
		$retarr = [];
 | 
						|
 | 
						|
		$timesheet_data = $this->stripReturnHandler( $this->getTimeSheetData( $user_id, $base_date ) );
 | 
						|
		if ( is_array( $timesheet_data ) ) {
 | 
						|
			$retarr = [
 | 
						|
					'timesheet_dates' => $timesheet_data['timesheet_dates'],
 | 
						|
					'pay_period_data' => $timesheet_data['pay_period_data'],
 | 
						|
 | 
						|
					'accumulated_user_date_total_data'            => $timesheet_data['accumulated_user_date_total_data'],
 | 
						|
					'pay_period_accumulated_user_date_total_data' => $timesheet_data['pay_period_accumulated_user_date_total_data'],
 | 
						|
					'timesheet_verify_data'                       => $timesheet_data['timesheet_verify_data'],
 | 
						|
			];
 | 
						|
		}
 | 
						|
 | 
						|
		//Debug::Arr($retarr, 'TimeSheet Total Data: ', __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
 | 
						|
		return $this->returnHandler( $retarr );
 | 
						|
	}
 | 
						|
 | 
						|
	private function _isUserEligibleToRecalculate( $u_obj, $ulf, $recalculate_company, $start_date, $end_date ) {
 | 
						|
		//Ignore terminated employees when recalculating company. However allow all employees to be recalculated if they are selected individually.
 | 
						|
		if (
 | 
						|
				( $u_obj->getStatus() == 10 || $ulf->getRecordCount() == 1 ) //Always recalculate if just a single employee is selected.
 | 
						|
				||
 | 
						|
				(
 | 
						|
						$u_obj->getStatus() != 10
 | 
						|
						&&
 | 
						|
						(
 | 
						|
								(
 | 
						|
										$recalculate_company == true
 | 
						|
										&&
 | 
						|
										( $u_obj->getTerminationDate() != '' && TTDate::getMiddleDayEpoch( $u_obj->getTerminationDate() ) > TTDate::getMiddleDayEpoch( $start_date ) ) //Only recaclulate terminated employees if they were terminated within this pay period.
 | 
						|
								)
 | 
						|
								||
 | 
						|
								(
 | 
						|
										$recalculate_company == false
 | 
						|
										&&
 | 
						|
										( $u_obj->getTerminationDate() != '' && TTDate::getMiddleDayEpoch( $u_obj->getTerminationDate() ) > ( TTDate::getMiddleDayEpoch( $start_date ) - ( 86400 * 90 ) ) ) //If the user was terminated more than 3 months ago, skip recalculating.
 | 
						|
								)
 | 
						|
								||
 | 
						|
								( $u_obj->getTerminationDate() == '' && TTDate::getMiddleDayEpoch( $u_obj->getUpdatedDate() ) > ( TTDate::getMiddleDayEpoch( $start_date ) - ( 86400 * 30 ) ) ) //If user is terminated and no termination date is set, only recalculate if the user record has been updated in the last 30 days.
 | 
						|
						)
 | 
						|
				)
 | 
						|
		) {
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * ReCalculate timesheet/policies
 | 
						|
	 * @param string|string[] $pay_period_ids UUID
 | 
						|
	 * @param string $user_ids                UUID
 | 
						|
	 * @return array|bool
 | 
						|
	 */
 | 
						|
	function reCalculateTimeSheet( $pay_period_ids, $user_ids = null ) {
 | 
						|
		//Debug::text('Recalculating Employee Timesheet: User ID: '. $user_ids .' Pay Period ID: '. $pay_period_ids, __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
		//Debug::setVerbosity(11);
 | 
						|
 | 
						|
		if ( !$this->getPermissionObject()->Check( 'punch', 'enabled' )
 | 
						|
				|| !( $this->getPermissionObject()->Check( 'punch', 'edit' ) || $this->getPermissionObject()->Check( 'punch', 'edit_child' ) ) ) {
 | 
						|
			return $this->getPermissionObject()->PermissionDenied();
 | 
						|
		}
 | 
						|
 | 
						|
		if ( Misc::isSystemLoadValid() == false ) { //Check system load before anything starts.
 | 
						|
			Debug::Text( 'ERROR: System load exceeded, preventing new recalculation processes from starting...', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
 | 
						|
			return $this->returnHandler( false );
 | 
						|
		}
 | 
						|
 | 
						|
		//Use report maximum execution time here because larger customers may need more time to recalculate many employees, similar to a report.
 | 
						|
		global $config_vars;
 | 
						|
		if ( isset( $config_vars['other']['report_maximum_execution_limit'] ) && $config_vars['other']['report_maximum_execution_limit'] != '' ) {
 | 
						|
			$maximum_execution_time = $config_vars['other']['report_maximum_execution_limit'];
 | 
						|
			Debug::Text( 'Setting maximum execution time: ' . $maximum_execution_time, __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
			ini_set( 'max_execution_time', $maximum_execution_time );
 | 
						|
		}
 | 
						|
 | 
						|
		//Make sure pay period is not CLOSED.
 | 
						|
		//We can re-calc on locked though.
 | 
						|
		$pplf = TTnew( 'PayPeriodListFactory' ); /** @var PayPeriodListFactory $pplf */
 | 
						|
		$pplf->getByIdList( $pay_period_ids, null, [ 'start_date' => 'asc' ] );
 | 
						|
		if ( $pplf->getRecordCount() > 0 ) {
 | 
						|
			foreach ( $pplf as $pp_obj ) {
 | 
						|
				Debug::Text( 'Recalculating Pay Period: ' . $pp_obj->getId() . ' Start Date: ' . TTDate::getDate( 'DATE', $pp_obj->getStartDate() ), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
				if ( $pp_obj->getStatus() != 20 ) {
 | 
						|
					$recalculate_company = false;
 | 
						|
 | 
						|
					$ulf = TTnew( 'UserListFactory' ); /** @var UserListFactory $ulf */
 | 
						|
					if ( is_array( $user_ids ) && count( $user_ids ) > 0 && isset( $user_ids[0] )
 | 
						|
							&& TTUUID::isUUID( $user_ids[0] ) && $user_ids[0] != TTUUID::getZeroID() && $user_ids[0] != TTUUID::getNotExistID() ) {
 | 
						|
						$ulf->getByIdAndCompanyId( $user_ids, $this->getCurrentCompanyObject()->getId() );
 | 
						|
					} else if ( $this->getPermissionObject()->Check( 'punch', 'edit' ) == true ) { //Make sure they have the permissions to recalculate all employees.
 | 
						|
						TTLog::addEntry( $this->getCurrentCompanyObject()->getId(), 500, TTi18n::gettext( 'Recalculating Company TimeSheet' ), $this->getCurrentUserObject()->getId(), 'user_date_total' );
 | 
						|
						$ulf->getByCompanyId( $this->getCurrentCompanyObject()->getId() );
 | 
						|
						$recalculate_company = true;
 | 
						|
					} else {
 | 
						|
						return $this->getPermissionObject()->PermissionDenied();
 | 
						|
					}
 | 
						|
 | 
						|
					if ( $ulf->getRecordCount() > 0 ) {
 | 
						|
						$start_date = $pp_obj->getStartDate();
 | 
						|
						$end_date = $pp_obj->getEndDate();
 | 
						|
						Debug::text( 'Found users to re-calculate: ' . $ulf->getRecordCount() . ' Start: ' . TTDate::getDate( 'DATE', $start_date ) . ' End: ' . TTDate::getDate( 'DATE', $end_date ), __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
 | 
						|
						if ( ( !isset( $config_vars['other']['enable_job_queue'] ) || $config_vars['other']['enable_job_queue'] == true ) && ( $pplf->getRecordCount() * $ulf->getRecordCount() ) > 200 ) {
 | 
						|
							$this->getProgressBarObject()->start( $this->getAPIMessageID(), $ulf->getRecordCount(), null, TTi18n::getText( 'ReCalculating Pay Period Ending' ) . ': ' . TTDate::getDate( 'DATE', $pp_obj->getEndDate() ) );
 | 
						|
 | 
						|
							$system_job_queue_batch_id = TTUUID::generateUUID();
 | 
						|
 | 
						|
							$x = 1;
 | 
						|
							foreach ( $ulf as $u_obj ) {
 | 
						|
								//Ignore terminated employees when recalculating company. However allow all employees to be recalculated if they are selected individually.
 | 
						|
								if ( $this->_isUserEligibleToRecalculate( $u_obj, $ulf, $recalculate_company, $start_date, $end_date ) == true ) {
 | 
						|
									TTLog::addEntry( $u_obj->getId(), 500, TTi18n::gettext( 'Recalculating Employee TimeSheet' ) . ': ' . $u_obj->getFullName() . ' ' . TTi18n::gettext( 'From' ) . ': ' . TTDate::getDate( 'DATE', $start_date ) . ' ' . TTi18n::gettext( 'To' ) . ': ' . TTDate::getDate( 'DATE', $end_date ), $this->getCurrentUserObject()->getId(), 'user_date_total' );
 | 
						|
									SystemJobQueue::Add( TTi18n::getText( 'ReCalculating Quick Exceptions' ), $system_job_queue_batch_id, 'CalculatePolicy', 'reCalculateForJobQueue', [ $u_obj->getID(), 'APITimeSheet', $start_date, $end_date ], 30 );
 | 
						|
 | 
						|
									$x++; //Only count valid users that we are recalculating.
 | 
						|
								}
 | 
						|
							}
 | 
						|
 | 
						|
							//Restart the progress bar with the true number of users to recalculate.
 | 
						|
							$this->getProgressBarObject()->start( $this->getAPIMessageID(), $x, null, TTi18n::getText( 'ReCalculating Pay Period Ending' ) . ': ' . TTDate::getDate( 'DATE', $pp_obj->getEndDate() ) );
 | 
						|
 | 
						|
							SystemJobQueue::waitUntilBatchCompleted( $system_job_queue_batch_id, $this->getAPIMessageID(), 5, 7200 ); //Run up to 2hrs.
 | 
						|
						} else {
 | 
						|
							$this->getProgressBarObject()->start( $this->getAPIMessageID(), $ulf->getRecordCount(), null, TTi18n::getText( 'ReCalculating Pay Period Ending' ) . ': ' . TTDate::getDate( 'DATE', $pp_obj->getEndDate() ) );
 | 
						|
 | 
						|
							$x = 1;
 | 
						|
							foreach ( $ulf as $u_obj ) {
 | 
						|
								if ( Misc::isSystemLoadValid() == false ) { //Check system load as the user could ask to calculate decades worth at a time.
 | 
						|
									Debug::Text( 'ERROR: System load exceeded, stopping recalculation...', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
									break;
 | 
						|
								}
 | 
						|
 | 
						|
								//Ignore terminated employees when recalculating company. However allow all employees to be recalculated if they are selected individually.
 | 
						|
								if ( $this->_isUserEligibleToRecalculate( $u_obj, $ulf, $recalculate_company, $start_date, $end_date ) == true ) {
 | 
						|
									TTLog::addEntry( $u_obj->getId(), 500, TTi18n::gettext( 'Recalculating Employee TimeSheet' ) . ': ' . $u_obj->getFullName() . ' ' . TTi18n::gettext( 'From' ) . ': ' . TTDate::getDate( 'DATE', $start_date ) . ' ' . TTi18n::gettext( 'To' ) . ': ' . TTDate::getDate( 'DATE', $end_date ), $this->getCurrentUserObject()->getId(), 'user_date_total' );
 | 
						|
 | 
						|
									$transaction_function = function () use ( $u_obj, $start_date, $end_date ) {
 | 
						|
										$cp = TTNew( 'CalculatePolicy' ); /** @var CalculatePolicy $cp */
 | 
						|
										$cp->setUserObject( $u_obj );
 | 
						|
										$cp->getUserObject()->setTransactionMode( 'REPEATABLE READ' );
 | 
						|
										$cp->addPendingCalculationDate( $start_date, $end_date );
 | 
						|
										$cp->calculate(); //This sets timezone itself.
 | 
						|
										$cp->Save();
 | 
						|
										$cp->getUserObject()->setTransactionMode(); //Back to default isolation level.
 | 
						|
 | 
						|
										return true;
 | 
						|
									};
 | 
						|
 | 
						|
									$u_obj->RetryTransaction( $transaction_function, 3, 3 ); //Set retry_sleep this fairly high so real-time punches have a chance to get saved between retries.
 | 
						|
								}
 | 
						|
								//							else {
 | 
						|
								//								Debug::text('Skipping inactive or terminated user: '. $u_obj->getID() .' Status: '. $u_obj->getStatus() .' Termination Date: '. TTDate::getDate('DATE', $u_obj->getTerminationDate() ) .' Updated Date: '. TTDate::getDate('DATE', $u_obj->getUpdatedDate() ), __FILE__, __LINE__, __METHOD__, 10);
 | 
						|
								//							}
 | 
						|
 | 
						|
								$this->getProgressBarObject()->set( $this->getAPIMessageID(), $x );
 | 
						|
 | 
						|
								$x++;
 | 
						|
							}
 | 
						|
 | 
						|
							$this->getProgressBarObject()->stop( $this->getAPIMessageID() );
 | 
						|
						}
 | 
						|
					} else {
 | 
						|
						Debug::text( 'No Users to calculate!', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					Debug::text( 'Pay Period is CLOSED: ', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return $this->returnHandler( true );
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Verify/Authorize timesheet
 | 
						|
	 * @param integer $user_id       User ID of the timesheet that is being verified.
 | 
						|
	 * @param integer $pay_period_id Pay Period ID of the timesheet that is being verified.
 | 
						|
	 * @param bool $enable_authorize Create authorization record or not, should only be TRUE if called from the TimeSheet view and not from the TimeSheet Authorization View.
 | 
						|
	 * @return array|bool
 | 
						|
	 */
 | 
						|
	function verifyTimeSheet( $user_id, $pay_period_id, $enable_authorize = true ) {
 | 
						|
		if ( $user_id != '' && $pay_period_id != '' ) {
 | 
						|
			Debug::text( 'Verifying Pay Period TimeSheet ', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
 | 
						|
			$pptsvlf = TTnew( 'PayPeriodTimeSheetVerifyListFactory' ); /** @var PayPeriodTimeSheetVerifyListFactory $pptsvlf  */
 | 
						|
 | 
						|
			$transaction_function = function () use ( $pptsvlf, $user_id, $pay_period_id, $enable_authorize ) {
 | 
						|
				$pptsvlf->setTransactionMode( 'REPEATABLE READ' );
 | 
						|
				$pptsvlf->StartTransaction();
 | 
						|
				$pptsvlf->getByPayPeriodIdAndUserId( $pay_period_id, $user_id );
 | 
						|
				if ( $pptsvlf->getRecordCount() == 0 ) {
 | 
						|
					Debug::text( 'Timesheet NOT verified by employee yet.', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
					$pptsvf = TTnew( 'PayPeriodTimeSheetVerifyFactory' ); /** @var PayPeriodTimeSheetVerifyFactory $pptsvf */
 | 
						|
				} else {
 | 
						|
					Debug::text( 'Timesheet re-verified by employee, or superior...', __FILE__, __LINE__, __METHOD__, 10 );
 | 
						|
					$pptsvf = $pptsvlf->getCurrent();
 | 
						|
				}
 | 
						|
 | 
						|
				$pptsvf->setCurrentUser( $this->getCurrentUserObject()->getId() );
 | 
						|
				$pptsvf->setUser( $user_id );
 | 
						|
				$pptsvf->setPayPeriod( $pay_period_id );
 | 
						|
 | 
						|
				$pptsvf->setEnableAuthorize( $enable_authorize );
 | 
						|
 | 
						|
				if ( $pptsvf->isValid() ) {
 | 
						|
					$pptsvf->Save( false );
 | 
						|
 | 
						|
					$retval = $this->returnHandler( $pptsvf->getId() );
 | 
						|
				} else {
 | 
						|
					$pptsvlf->FailTransaction();
 | 
						|
 | 
						|
					$retval = $this->returnHandler( false, 'VALIDATION', TTi18n::getText( 'INVALID DATA' ), [ 'errors' => $pptsvf->Validator->getErrorsArray() ], [ 'total_records' => 1, 'valid_records' => 0 ] );
 | 
						|
				}
 | 
						|
 | 
						|
				$pptsvlf->CommitTransaction();
 | 
						|
				$pptsvlf->setTransactionMode();
 | 
						|
 | 
						|
				return [ $retval ];
 | 
						|
			};
 | 
						|
 | 
						|
			[ $retval ] = $pptsvlf->RetryTransaction( $transaction_function, 3, 3 ); //Set retry_sleep this fairly high so real-time punches have a chance to get saved between retries.
 | 
						|
 | 
						|
			return $retval; //This is a returnHandler()
 | 
						|
		}
 | 
						|
 | 
						|
		return $this->returnHandler( false );
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
?>
 |