1876 lines
86 KiB
PHP
1876 lines
86 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 Modules\Schedule
|
|
*/
|
|
class ScheduleListFactory extends ScheduleFactory implements IteratorAggregate {
|
|
|
|
/**
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return $this
|
|
*/
|
|
function getAll( $limit = null, $page = null, $where = null, $order = null ) {
|
|
$query = '
|
|
select *
|
|
from ' . $this->getTable() . '
|
|
WHERE deleted = 0';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, null, $limit, $page );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $id UUID
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getById( $id, $where = null, $order = null ) {
|
|
if ( $id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$ph = [
|
|
'id' => TTUUID::castUUID( $id ),
|
|
];
|
|
|
|
$query = '
|
|
select *
|
|
from ' . $this->getTable() . '
|
|
where id = ?
|
|
AND deleted = 0';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $company_id UUID
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByCompanyID( $company_id, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'a.start_time' => 'asc', 'a.status_id' => 'desc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$uf = new UserFactory();
|
|
|
|
$ph = [
|
|
'company_id' => TTUUID::castUUID( $company_id ),
|
|
];
|
|
|
|
//Status sorting MUST be desc first, otherwise transfer punches are completely out of order.
|
|
$query = '
|
|
select a.*
|
|
from ' . $this->getTable() . ' as a
|
|
LEFT JOIN ' . $uf->getTable() . ' as c ON ( a.user_id = c.id AND c.deleted = 0 )
|
|
where a.company_id = ?
|
|
AND a.deleted = 0
|
|
';
|
|
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $id UUID
|
|
* @param string $company_id UUID
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByIdAndCompanyId( $id, $company_id ) {
|
|
return $this->getByCompanyIDAndId( $company_id, $id );
|
|
}
|
|
|
|
/**
|
|
* @param string $company_id UUID
|
|
* @param string $id UUID
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByCompanyIDAndId( $company_id, $id ) {
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$uf = new UserFactory();
|
|
|
|
$ph = [
|
|
'company_id' => TTUUID::castUUID( $company_id ),
|
|
'company_id2' => TTUUID::castUUID( $company_id ),
|
|
];
|
|
|
|
//Status sorting MUST be desc first, otherwise transfer punches are completely out of order.
|
|
//Always include the user_id, this is required for mass edit to function correctly and not assign schedules to OPEN employee all the time.
|
|
$query = '
|
|
select a.*
|
|
from ' . $this->getTable() . ' as a
|
|
LEFT JOIN ' . $uf->getTable() . ' as c ON ( a.user_id = c.id AND c.deleted = 0 )
|
|
where ( c.company_id = ? OR a.company_id = ? )
|
|
AND a.id in (' . $this->getListSQL( $id, $ph, 'uuid' ) . ')
|
|
AND ( a.deleted = 0 )
|
|
ORDER BY a.start_time asc, a.status_id desc
|
|
';
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $date_stamp EPOCH
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByUserIdAndDateStamp( $user_id, $date_stamp, $where = null, $order = null ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $date_stamp == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'start_time' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$ph = [
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'date_stamp' => $this->db->BindDate( $date_stamp ),
|
|
];
|
|
|
|
$query = '
|
|
select *
|
|
from ' . $this->getTable() . '
|
|
where user_id = ?
|
|
AND date_stamp = ?
|
|
AND deleted = 0';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $date_stamp EPOCH
|
|
* @param int $status_id
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByUserIdAndDateStampAndStatus( $user_id, $date_stamp, $status_id, $where = null, $order = null ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $date_stamp == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $status_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'start_time' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$ph = [
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'date_stamp' => $this->db->BindDate( $date_stamp ),
|
|
'status_id' => (int)$status_id,
|
|
];
|
|
|
|
$query = '
|
|
select *
|
|
from ' . $this->getTable() . '
|
|
where user_id = ?
|
|
AND date_stamp = ?
|
|
AND status_id = ?
|
|
AND deleted = 0';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $start_date EPOCH
|
|
* @param int $end_date EPOCH
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByUserIdAndStartDateAndEndDate( $user_id, $start_date, $end_date, $where = null, $order = null ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $start_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $end_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$additional_order_fields = [ 'a.date_stamp' ];
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'a.date_stamp' => 'asc', 'a.status_id' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$ph = [
|
|
'start_date' => $this->db->BindDate( $start_date ),
|
|
'end_date' => $this->db->BindDate( $end_date ),
|
|
];
|
|
|
|
$query = '
|
|
select a.*
|
|
from ' . $this->getTable() . ' as a
|
|
where a.date_stamp >= ?
|
|
AND a.date_stamp <= ?
|
|
AND a.user_id in (' . $this->getListSQL( $user_id, $ph, 'uuid' ) . ')
|
|
AND ( a.deleted = 0 )
|
|
';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict, $additional_order_fields );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $start_date EPOCH
|
|
* @param int $end_date EPOCH
|
|
* @param int|array $status_id INT
|
|
* @param string|array $exclude_id UUID
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByUserIdAndStartDateAndEndDateAndStatusIdAndExcludeId( $user_id, $start_date, $end_date, $status_id, $exclude_id, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $start_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $end_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$additional_order_fields = [ 'a.date_stamp' ];
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'a.date_stamp' => 'asc', 'a.start_time' => 'asc', 'a.status_id' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$ph = [
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'start_date' => $this->db->BindDate( $start_date ),
|
|
'end_date' => $this->db->BindDate( $end_date ),
|
|
];
|
|
|
|
$query = '
|
|
select a.*
|
|
from ' . $this->getTable() . ' as a
|
|
where a.user_id = ?
|
|
AND a.date_stamp >= ?
|
|
AND a.date_stamp <= ? ';
|
|
|
|
if ( !empty( $status_id ) ) {
|
|
$query .= ' AND a.status_id in (' . $this->getListSQL( $status_id, $ph, 'int' ) . ') ';
|
|
}
|
|
|
|
if ( !empty( $exclude_id ) ) {
|
|
$query .= ' AND a.id not in (' . $this->getListSQL( $exclude_id, $ph, 'uuid' ) . ') ';
|
|
}
|
|
|
|
$query .= ' AND ( a.deleted = 0 )';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict, $additional_order_fields );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $epoch EPOCH
|
|
* @param int $week_start_epoch EPOCH
|
|
* @return bool|int
|
|
*/
|
|
function getWeekWorkTimeSumByUserIDAndEpochAndStartWeekEpoch( $user_id, $epoch, $week_start_epoch ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $epoch == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $week_start_epoch == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$ph = [
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'week_start_epoch' => $this->db->BindDate( $week_start_epoch ),
|
|
'epoch' => $this->db->BindDate( $epoch ),
|
|
];
|
|
|
|
//DO NOT Include paid absences. Only count regular time towards weekly overtime.
|
|
//And other weekly overtime polices!
|
|
$query = '
|
|
select sum(a.total_time)
|
|
from ' . $this->getTable() . ' as a
|
|
where
|
|
a.user_id = ?
|
|
AND a.date_stamp >= ?
|
|
AND a.date_stamp < ?
|
|
AND a.status_id = 10
|
|
AND a.deleted = 0
|
|
';
|
|
$total = $this->db->GetOne( $query, $ph );
|
|
|
|
if ( $total === false ) {
|
|
$total = 0;
|
|
}
|
|
Debug::text( 'Total: ' . $total, __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return $total;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $type_id
|
|
* @param $direction
|
|
* @param int $date EPOCH
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getByUserIdAndTypeAndDirectionFromDate( $user_id, $type_id, $direction, $date, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $type_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $direction == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $order == null ) {
|
|
$strict = false;
|
|
|
|
$order = [ 'a.date_stamp' => 'asc' ]; //When direction is after, we need to get the days in the proper order (ASC)
|
|
if ( strtolower( $direction ) == 'before' ) {
|
|
$order = [ 'a.date_stamp' => 'desc' ]; //When direction is before, we need to get the days in the proper order (DESC)
|
|
$direction = '<';
|
|
} else if ( strtolower( $direction ) == 'after' ) {
|
|
$direction = '>';
|
|
} else {
|
|
return false;
|
|
}
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
$ph = [
|
|
'date' => $this->db->BindDate( $date ),
|
|
'type_id' => (int)$type_id,
|
|
];
|
|
|
|
$query = '
|
|
select a.*
|
|
from ' . $this->getTable() . ' as a
|
|
where a.date_stamp ' . $direction . ' ?
|
|
AND a.status_id = ?
|
|
AND a.user_id in (' . $this->getListSQL( $user_id, $ph, 'uuid' ) . ')
|
|
AND ( a.deleted = 0 )
|
|
';
|
|
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page );
|
|
|
|
//Debug::Query( $query, $ph .' Limit: '. $limit, __FILE__, __LINE__, __METHOD__, 10);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $company_id UUID
|
|
* @param string $user_id UUID
|
|
* @param int $start_date EPOCH
|
|
* @param int $end_date EPOCH
|
|
* @param string $id UUID
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getConflictingByCompanyIdAndUserIdAndStartDateAndEndDate( $company_id, $user_id, $start_date, $end_date, $id = null, $where = null, $order = null ) {
|
|
Debug::Text( 'User ID: ' . $user_id . ' Start Date: ' . $start_date . ' End Date: ' . $end_date, __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $start_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $end_date == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $id == '' ) {
|
|
$id = TTUUID::getZeroId(); //Leaving this as NULL can cause the SQL query to not return rows when it should.
|
|
}
|
|
|
|
$start_timestamp = $this->db->BindTimeStamp( (int)$start_date );
|
|
$end_timestamp = $this->db->BindTimeStamp( (int)$end_date );
|
|
|
|
$ph = [
|
|
'company_id' => TTUUID::castUUID( $company_id ),
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'start_date_a' => $this->db->BindDate( ( $start_date - 86400 ) ), //Need to expand the date_stamp restriction by at least a day to cover shifts that span midnight.
|
|
'end_date_b' => $this->db->BindDate( ( $end_date + 86400 ) ), //Need to expand the date_stamp restriction by at least a day to cover shifts that span midnight.
|
|
'id' => TTUUID::castUUID( $id ),
|
|
'start_date1' => $start_timestamp,
|
|
'end_date1' => $end_timestamp,
|
|
'start_date2' => $start_timestamp,
|
|
'end_date2' => $end_timestamp,
|
|
'start_date3' => $start_timestamp,
|
|
'end_date3' => $end_timestamp,
|
|
'start_date4' => $start_timestamp,
|
|
'end_date4' => $end_timestamp,
|
|
'start_date5' => $start_timestamp,
|
|
'end_date5' => $end_timestamp,
|
|
];
|
|
|
|
//Add filter on date_stamp for optimization
|
|
// Make sure we ignore any records that have been replaced by other records already.
|
|
$query = '
|
|
SELECT a.*
|
|
FROM ' . $this->getTable() . ' as a
|
|
LEFT JOIN ' . $this->getTable() . ' as b ON ( a.id = b.replaced_id AND b.deleted = 0 )
|
|
WHERE a.company_id = ?
|
|
AND a.user_id = ?
|
|
AND a.date_stamp >= ?
|
|
AND a.date_stamp <= ?
|
|
AND a.id != ?
|
|
AND b.id IS NULL
|
|
AND
|
|
(
|
|
( a.start_time >= ? AND a.end_time <= ? )
|
|
OR
|
|
( a.start_time >= ? AND a.start_time < ? )
|
|
OR
|
|
( a.end_time > ? AND a.end_time <= ? )
|
|
OR
|
|
( a.start_time <= ? AND a.end_time >= ? )
|
|
OR
|
|
( a.start_time = ? AND a.end_time = ? )
|
|
)
|
|
AND ( a.deleted = 0 )
|
|
ORDER BY start_time, user_id, created_date';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph );
|
|
|
|
//Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $user_id UUID
|
|
* @param int $epoch EPOCH
|
|
* @return bool|mixed
|
|
*/
|
|
function getScheduleObjectByUserIdAndEpoch( $user_id, $epoch ) {
|
|
if ( $user_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $epoch == '' ) {
|
|
return false;
|
|
}
|
|
|
|
//Need to handle schedules on next/previous dates from when the punch is.
|
|
//ie: if the schedule started on 11:30PM on Jul 5th and the punch is 01:00AM on Jul 6th.
|
|
//These two functions are almost identical: PunchFactory::findScheduleId() and ScheduleListFactory::getScheduleObjectByUserIdAndEpoch()
|
|
$slf = new ScheduleListFactory();
|
|
$slf->getByUserIdAndStartDateAndEndDate( $user_id, ( TTDate::getMiddleDayEpoch( $epoch ) - 86400 ), ( TTDate::getMiddleDayEpoch( $epoch ) + 86400 ), null, [ 'a.date_stamp' => 'asc', 'a.status_id' => 'asc', 'a.start_time' => 'desc' ] );
|
|
if ( $slf->getRecordCount() > 0 ) {
|
|
Debug::Text( ' Found Scheduled Shift! User: ' . $user_id . ' Epoch: ' . TTDate::getDATE( 'DATE+TIME', $epoch ) . '(' . $epoch . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
$retval = false;
|
|
$best_diff = false;
|
|
//Check for schedule policy
|
|
foreach ( $slf as $s_obj ) {
|
|
Debug::text( ' Checking Schedule ID: ' . $s_obj->getID() . ' Start: ' . TTDate::getDate( 'DATE+TIME', $s_obj->getStartTime() ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $s_obj->getEndTime() ), __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
//If the Start/Stop window is large (ie: 6-8hrs) we need to find the closest schedule.
|
|
$schedule_diff = $s_obj->inScheduleDifference( $epoch );
|
|
|
|
//If its an absent shift *within the start/stop window** as determined by $schedule_diff !== false
|
|
// weight the schedule difference to at least that of the start/stop window so we prefer working shifts by that are within that amount of time. Almost like a reverse start/stop window.
|
|
// See PunchFactory::getDefaultPunchSettings() for more comments on this.
|
|
if ( $schedule_diff !== false && $s_obj->getStatus() == 20 ) { //20=Absent
|
|
$schedule_diff += $s_obj->getStartStopWindow();
|
|
}
|
|
|
|
if ( $schedule_diff === 0 ) {
|
|
Debug::text( ' Within schedule times. ', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return $s_obj;
|
|
} else {
|
|
if ( $schedule_diff > 0 && ( $best_diff === false || $schedule_diff < $best_diff ) ) {
|
|
Debug::text( ' Within schedule start/stop time by: ' . $schedule_diff . ' Prev Best Diff: ' . $best_diff, __FILE__, __LINE__, __METHOD__, 10 );
|
|
$best_diff = $schedule_diff;
|
|
$retval = $s_obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( isset( $retval ) && is_object( $retval ) ) {
|
|
return $retval;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Find all *committed* open shifts that conflict, so they can be entered in the replaced_id field.
|
|
* @param string $company_id UUID
|
|
* @param $user_id
|
|
* @param $start_time
|
|
* @param $end_time
|
|
* @param string $branch_id UUID
|
|
* @param string $department_id UUID
|
|
* @param string $job_id UUID
|
|
* @param string $job_item_id UUID
|
|
* @param int $replaced_id
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
* @throws DBError
|
|
*/
|
|
function getConflictingOpenShiftSchedule( $company_id, $user_id, $start_time, $end_time, $branch_id, $department_id, $job_id, $job_item_id, $absence_policy_id, $replaced_id = 0, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $company_id == '' || $start_time == '' || $end_time == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( $order == null ) {
|
|
$order = [ 'a.created_date' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
|
|
Debug::Text( 'Getting conflicting Open Shifts...', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
$uf = new UserFactory();
|
|
$rsf = new RecurringScheduleFactory();
|
|
|
|
$ph = [
|
|
'user_id' => TTUUID::castUUID( $user_id ),
|
|
'company_id' => TTUUID::castUUID( $company_id ),
|
|
'open_user_id' => TTUUID::getZeroID(), //Open Shift
|
|
'start_time' => $this->db->BindTimeStamp( (int)$start_time ),
|
|
'end_time' => $this->db->BindTimeStamp( (int)$end_time ),
|
|
'branch_id' => TTUUID::castUUID( $branch_id ),
|
|
'department_id' => TTUUID::castUUID( $department_id ),
|
|
'job_id' => TTUUID::castUUID( $job_id ),
|
|
'job_item_id' => TTUUID::castUUID( $job_item_id ),
|
|
'absence_policy_id' => TTUUID::castUUID( $absence_policy_id ),
|
|
];
|
|
|
|
|
|
//Handle cases where the user edits/saves (no changes) a recurring schedule that is already filling an OPEN shift. The commit shift shouldn't also fill a commited OPEN shift too.
|
|
// We do this by joining to the recurring_schedule table and ensuring that the committed shift doesn't override a recurring schedule.
|
|
$query = '
|
|
SELECT a.*
|
|
FROM ' . $this->getTable() . ' as a
|
|
LEFT JOIN ' . $this->getTable() . ' as b ON ( a.id = b.replaced_id AND b.deleted = 0 )
|
|
LEFT JOIN ' . $uf->getTable() . ' as uf ON ( a.user_id = uf.id AND uf.deleted = 0 )
|
|
LEFT JOIN ' . $rsf->getTable() . ' AS rsf ON (
|
|
rsf.user_id = ?
|
|
AND a.date_stamp = rsf.date_stamp
|
|
AND a.start_time = rsf.start_time
|
|
AND a.end_Time = rsf.end_time
|
|
AND rsf.deleted = 0
|
|
)
|
|
|
|
WHERE ( a.company_id = ?
|
|
AND a.user_id = ?
|
|
AND a.start_time = ?
|
|
AND a.end_time = ?
|
|
AND a.branch_id = ?
|
|
AND a.department_id = ?
|
|
AND a.job_id = ?
|
|
AND a.job_item_id = ?
|
|
AND ( a.status_id = 10 OR ( a.status_id = 20 AND a.absence_policy_id = ? ) )
|
|
AND ( a.replaced_id = \'' . TTUUID::getZeroID() . '\' AND b.replaced_id IS NULL )
|
|
AND ( rsf.id IS NULL )
|
|
AND a.deleted = 0
|
|
)
|
|
';
|
|
|
|
if ( TTUUID::isUUID( $replaced_id ) && $replaced_id != TTUUID::getZeroID() && $replaced_id != TTUUID::getNotExistID() ) {
|
|
//Make sure when passed a $replaced_id, we also make sure that record still matches all necessary items to fill the original open shift.
|
|
$ph += [
|
|
'user_id2' => TTUUID::getZeroID(), //Open Shift
|
|
'start_time2' => $this->db->BindTimeStamp( (int)$start_time ),
|
|
'end_time2' => $this->db->BindTimeStamp( (int)$end_time ),
|
|
'branch_id2' => TTUUID::castUUID( $branch_id ),
|
|
'department_id2' => TTUUID::castUUID( $department_id ),
|
|
'job_id2' => TTUUID::castUUID( $job_id ),
|
|
'job_item_id2' => TTUUID::castUUID( $job_item_id ),
|
|
'absence_policy_id2' => TTUUID::castUUID( $absence_policy_id ),
|
|
];
|
|
|
|
$query .= ' OR ( a.id = \'' . TTUUID::castUUID( $replaced_id ) . '\' AND a.user_id = ? AND a.start_time = ? AND a.end_time = ? AND a.branch_id = ? AND a.department_id = ? AND a.job_id = ? AND a.job_item_id = ? AND ( a.status_id = 10 OR ( a.status_id = 20 AND a.absence_policy_id = ? ) ) AND a.deleted = 0 ) ';
|
|
$order = ( [ 'a.id' => ' = \'' . TTUUID::castUUID( $replaced_id ) . '\' desc' ] + $order );
|
|
}
|
|
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page );
|
|
//Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param $company_id
|
|
* @param $filter_data
|
|
* @param null $limit
|
|
* @param null $page
|
|
* @param null $where
|
|
* @param null $order
|
|
* @return array|bool
|
|
* @throws ReflectionException
|
|
*/
|
|
function getOverriddenOpenShiftRecurringSchedules( $company_id, $filter_data, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
//Must always force the same order as thats critical to this function working.
|
|
$order = [ 'layer_order' => 'asc', 'a.user_id' => 'asc', 'a.start_time' => 'asc' ];
|
|
$strict = false;
|
|
|
|
//if ( $order == null ) {
|
|
// $order = [ 'layer_order' => 'asc', 'uf.last_name' => 'asc', 'a.start_time' => 'asc' ];
|
|
// $strict = false;
|
|
//} else {
|
|
// $strict = true;
|
|
//}
|
|
|
|
Debug::Text( 'Getting overrriden Open Shifts...', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
//Debug::Arr($order, 'Order Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
//Debug::Arr($filter_data, 'Filter Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
if ( isset( $filter_data['pay_period_ids'] ) ) {
|
|
$filter_data['pay_period_id'] = $filter_data['pay_period_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['user_status_ids'] ) ) {
|
|
$filter_data['user_status_id'] = $filter_data['user_status_ids'];
|
|
}
|
|
if ( isset( $filter_data['user_title_ids'] ) ) {
|
|
$filter_data['title_id'] = $filter_data['user_title_ids'];
|
|
}
|
|
if ( isset( $filter_data['group_ids'] ) ) {
|
|
$filter_data['group_id'] = $filter_data['group_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_branch_ids'] ) ) {
|
|
$filter_data['default_branch_id'] = $filter_data['default_branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_department_ids'] ) ) {
|
|
$filter_data['default_department_id'] = $filter_data['default_department_ids'];
|
|
}
|
|
if ( isset( $filter_data['status_ids'] ) ) {
|
|
$filter_data['status_id'] = $filter_data['status_ids'];
|
|
}
|
|
if ( isset( $filter_data['branch_ids'] ) ) {
|
|
$filter_data['schedule_branch_id'] = $filter_data['branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['department_ids'] ) ) {
|
|
$filter_data['schedule_department_id'] = $filter_data['department_ids'];
|
|
}
|
|
if ( isset( $filter_data['schedule_branch_ids'] ) ) {
|
|
$filter_data['schedule_branch_id'] = $filter_data['schedule_branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['schedule_department_ids'] ) ) {
|
|
$filter_data['schedule_department_id'] = $filter_data['schedule_department_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['exclude_job_ids'] ) ) {
|
|
$filter_data['exclude_id'] = $filter_data['exclude_job_ids'];
|
|
}
|
|
if ( isset( $filter_data['include_job_ids'] ) ) {
|
|
$filter_data['include_job_id'] = $filter_data['include_job_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_group_ids'] ) ) {
|
|
$filter_data['job_group_id'] = $filter_data['job_group_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_item_ids'] ) ) {
|
|
$filter_data['job_item_id'] = $filter_data['job_item_ids'];
|
|
}
|
|
|
|
//Since these are OPEN shifts, none of them are assigned to pay periods. So we need to convert filtered Pay Period IDs to date ranges instead.
|
|
if ( isset( $filter_data['pay_period_id'] ) && !isset( $filter_data['start_date'] ) && !isset( $filter_data['end_date'] ) ) {
|
|
$pplf = TTnew( 'PayPeriodListFactory' ); /** @var PayPeriodListFactory $pplf */
|
|
$pay_period_dates = $pplf->getStartAndEndDateRangeFromCompanyIdAndPayPeriodId( $company_id, $filter_data['pay_period_id'] );
|
|
if ( is_array( $pay_period_dates ) ) {
|
|
$filter_data['start_date'] = $pay_period_dates['start_date'];
|
|
$filter_data['end_date'] = $pay_period_dates['end_date'];
|
|
Debug::Arr( $filter_data['pay_period_id'], ' Converted Pay Period IDs to Dates: Start: ' . TTDate::getDate( 'DATE+TIME', $pay_period_dates['start_date'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $pay_period_dates['end_date'] ), __FILE__, __LINE__, __METHOD__, 10 );
|
|
unset( $filter_data['pay_period_id'] );
|
|
}
|
|
|
|
unset( $pplf, $pay_period_dates );
|
|
}
|
|
|
|
$uf = new UserFactory();
|
|
$apf = new AbsencePolicyFactory();
|
|
$sf = new ScheduleFactory();
|
|
$rsf = new RecurringScheduleFactory();
|
|
$rscf = new RecurringScheduleControlFactory();
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$jf = new JobFactory();
|
|
$jif = new JobItemFactory();
|
|
}
|
|
|
|
$ph['company_id1'] = TTUUID::castUUID( $company_id );
|
|
|
|
//Check for committed OPEN schedules that override open recurring schedules.
|
|
// Check against replaced_id to ensure we ignore cases where 1 of 2 recurring OPEN shifts are overridden by a committed OPEN shift (basically an edit/save without any changes),
|
|
// then the remaining recurring OPEN shift is filled by an employee by editing the OPEN shift, changing the employee, and saving.
|
|
// Essentially we are two levels deep of overrides here, so there should still be one OPEN shift displayed in this case.
|
|
$query = '
|
|
SELECT
|
|
a.id as id,
|
|
a.company_id as company_id,
|
|
a.user_id as user_id,
|
|
a.status_id as status_id,
|
|
a.date_stamp as date_stamp,
|
|
a.start_time as start_time,
|
|
a.end_time as end_time,
|
|
|
|
a.branch_id as branch_id,
|
|
a.department_id as department_id,
|
|
a.job_id as job_id,
|
|
a.job_item_id as job_item_id,
|
|
|
|
uf.default_branch_id as default_branch_id,
|
|
uf.default_department_id as default_department_id,
|
|
uf.default_job_id as default_job_id,
|
|
uf.default_job_item_id as default_job_item_id,
|
|
|
|
a.total_time as total_time,
|
|
a.schedule_policy_id as schedule_policy_id,
|
|
a.absence_policy_id as absence_policy_id,
|
|
a.deleted as deleted,
|
|
a.layer_order as layer_order
|
|
FROM
|
|
(
|
|
SELECT
|
|
rsf_b.id as id,
|
|
rsf_b.company_id as company_id,
|
|
rsf_b.user_id as user_id,
|
|
rsf_b.status_id as status_id,
|
|
rsf_b.date_stamp as date_stamp,
|
|
rsf_b.start_time as start_time,
|
|
rsf_b.end_time as end_time,
|
|
|
|
rsf_b.branch_id as branch_id,
|
|
rsf_b.department_id as department_id,
|
|
rsf_b.job_id as job_id,
|
|
rsf_b.job_item_id as job_item_id,
|
|
rsf_b.total_time as total_time,
|
|
rsf_b.schedule_policy_id as schedule_policy_id,
|
|
rsf_b.absence_policy_id as absence_policy_id,
|
|
rsf_b.deleted as deleted,
|
|
CASE WHEN rsf_b.user_id = \'' . TTUUID::getZeroID() . '\' THEN 8 ELSE 1 END as layer_order
|
|
FROM ' . $rsf->getTable() . ' as rsf_b
|
|
LEFT JOIN ' . $rscf->getTable() . ' as rscf_b ON ( rsf_b.recurring_schedule_control_id = rscf_b.id )
|
|
|
|
WHERE rsf_b.company_id = ?
|
|
';
|
|
|
|
$query .= ( isset( $filter_data['start_date'] ) ) ? $this->getWhereClauseSQL( 'rsf_b.start_time', $filter_data['start_date'], 'start_timestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_date'] ) ) ? $this->getWhereClauseSQL( 'rsf_b.start_time', $filter_data['end_date'], 'end_timestamp', $ph ) : null;
|
|
|
|
$query .= '
|
|
AND ( rsf_b.deleted = 0 AND rscf_b.deleted = 0 )
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
sf_b.id as id,
|
|
sf_b.company_id as company_id,
|
|
sf_b.user_id as user_id,
|
|
sf_b.status_id as status_id,
|
|
sf_b.date_stamp as date_stamp,
|
|
sf_b.start_time as start_time,
|
|
sf_b.end_time as end_time,
|
|
|
|
sf_b.branch_id as branch_id,
|
|
sf_b.department_id as department_id,
|
|
sf_b.job_id as job_id,
|
|
sf_b.job_item_id as job_item_id,
|
|
sf_b.total_time as total_time,
|
|
sf_b.schedule_policy_id as schedule_policy_id,
|
|
sf_b.absence_policy_id as absence_policy_id,
|
|
sf_b.deleted as deleted,
|
|
CASE WHEN sf_b.user_id = \'' . TTUUID::getZeroID() . '\' THEN 9 ELSE 2 END as layer_order
|
|
FROM ' . $sf->getTable() . ' as sf_b
|
|
WHERE sf_b.company_id = ?
|
|
';
|
|
|
|
$ph['company_id2'] = TTUUID::castUUID( $company_id );
|
|
|
|
$query .= ( isset( $filter_data['start_date'] ) ) ? $this->getWhereClauseSQL( 'sf_b.start_time', $filter_data['start_date'], 'start_timestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_date'] ) ) ? $this->getWhereClauseSQL( 'sf_b.start_time', $filter_data['end_date'], 'end_timestamp', $ph ) : null;
|
|
|
|
$query .= '
|
|
|
|
AND ( sf_b.deleted = 0 )
|
|
) as a
|
|
LEFT JOIN ' . $uf->getTable() . ' as uf ON a.user_id = uf.id
|
|
LEFT JOIN ' . $apf->getTable() . ' as apf ON a.absence_policy_id = apf.id
|
|
';
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ' LEFT JOIN ' . $jf->getTable() . ' as x ON a.job_id = x.id';
|
|
$query .= ' LEFT JOIN ' . $jif->getTable() . ' as y ON a.job_item_id = y.id';
|
|
}
|
|
|
|
$ph['company_id3'] = TTUUID::castUUID( $company_id );
|
|
$query .= ' WHERE a.company_id = ? ';
|
|
|
|
$query .= ( isset( $filter_data['schedule_branch_id'] ) ) ? $this->getWhereClauseSQL( 'a.branch_id', $filter_data['schedule_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_department_id'] ) ) ? $this->getWhereClauseSQL( 'a.department_id', $filter_data['schedule_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['status_id'] ) ) ? $this->getWhereClauseSQL( 'a.status_id', $filter_data['status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.schedule_policy_id', $filter_data['schedule_policy_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['absence_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.absence_policy_id', $filter_data['absence_policy_id'], 'uuid_list', $ph ) : null;
|
|
|
|
//$query .= ( isset($filter_data['pay_period_id']) ) ? $this->getWhereClauseSQL( 'a.pay_period_id', $filter_data['pay_period_id'], 'uuid_list', $ph ) : NULL;
|
|
|
|
$query .= ( isset( $filter_data['user_status_id'] ) ) ? $this->getWhereClauseSQL( 'uf.status_id', $filter_data['user_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['group_id'] ) ) ? $this->getWhereClauseSQL( 'uf.group_id', $filter_data['group_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_branch_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_branch_id', $filter_data['default_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_department_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_department_id', $filter_data['default_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['title_id'] ) ) ? $this->getWhereClauseSQL( 'uf.title_id', $filter_data['title_id'], 'uuid_list', $ph ) : null;
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ( isset( $filter_data['job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_status_id'] ) ) ? $this->getWhereClauseSQL( 'x.status_id', $filter_data['job_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['include_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['include_job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['exclude_job_id'], 'not_uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_group_id'] ) ) ? $this->getWhereClauseSQL( 'x.group_id', $filter_data['job_group_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_item_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_item_id', $filter_data['job_item_id'], 'uuid_list', $ph ) : null;
|
|
}
|
|
|
|
//These aren't needed here, asn they are filtered in the UNION SELECTs above. This seems to slow things down substantially in some cases.
|
|
//$query .= ( isset($filter_data['start_date']) ) ? $this->getWhereClauseSQL( 'a.start_time', $filter_data['start_date'], 'start_timestamp', $ph ) : NULL;
|
|
//$query .= ( isset($filter_data['end_date']) ) ? $this->getWhereClauseSQL( 'a.start_time', $filter_data['end_date'], 'end_timestamp', $ph ) : NULL;
|
|
|
|
$query .= '
|
|
AND ( a.deleted = 0 AND ( uf.deleted IS NULL OR uf.deleted = 0 ) )
|
|
';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict );
|
|
|
|
|
|
$rows = $this->db->GetAll( $query, $ph );
|
|
Debug::Text( ' Shifts to process: '. count($rows), __FILE__, __LINE__, __METHOD__, 10 );
|
|
//Debug::Query($query, $ph, __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
if ( is_array( $rows ) ) {
|
|
$i = 0;
|
|
$retarr = [];
|
|
$recurring_schedules = [];
|
|
foreach( $rows as $key => $row ) {
|
|
$row_iso_date_stamp = TTDate::getISODateStamp( strtotime( $row['start_time'] ) );
|
|
|
|
//Debug::Text( 'Row: ' . $row['id'] . '['. $row['layer_order'] .'] ( User: '. $row['user_id'] .' Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
if ( $row['layer_order'] == 1 ) { //Recurring shifts
|
|
$recurring_schedules[ $row['user_id'] ][$row_iso_date_stamp][] = $row;
|
|
} else if ( $row['layer_order'] == 2 ) { //Override shifts
|
|
if ( isset($recurring_schedules[ $row['user_id'] ]) ) {
|
|
foreach ( $recurring_schedules[$row['user_id']] as $rs_user_date => $rs_user_date_rows ) {
|
|
foreach ( $rs_user_date_rows as $rs_key => $rs_row ) {
|
|
//Committed shifts overlap recurring shifts in any way whatsoever.
|
|
if ( $row['user_id'] == $rs_row['user_id']
|
|
&& $row['user_id'] != TTUUID::getZeroID()
|
|
&& TTDate::isTimeOverLap( strtotime( $row['start_time'] ), strtotime( $row['end_time'] ), strtotime( $rs_row['start_time'] ), strtotime( $rs_row['end_time'] ) )
|
|
&& ( $row['branch_id'] == $rs_row['branch_id'] || ( $rs_row['branch_id'] == TTUUID::getNotExistID() && ( $row['branch_id'] == TTUUID::getZeroID() || $rs_row['default_branch_id'] == $row['default_branch_id'] ) ) || ( $row['branch_id'] == TTUUID::getNotExistID() && $rs_row['branch_id'] == $row['default_branch_id'] ) )
|
|
&& ( $row['department_id'] == $rs_row['department_id'] || ( $rs_row['department_id'] == TTUUID::getNotExistID() && ( $row['department_id'] == TTUUID::getZeroID() || $rs_row['default_department_id'] == $row['default_department_id'] ) ) || ( $row['department_id'] == TTUUID::getNotExistID() && $rs_row['department_id'] == $row['default_department_id'] ) )
|
|
&& ( $row['job_id'] == $rs_row['job_id'] || ( $rs_row['job_id'] == TTUUID::getNotExistID() && ( $row['job_id'] == TTUUID::getZeroID() || $rs_row['default_job_id'] == $row['default_job_id'] ) ) || ( $row['job_id'] == TTUUID::getNotExistID() && $rs_row['job_id'] == $row['default_job_id'] ) )
|
|
&& ( $row['job_item_id'] == $rs_row['job_item_id'] || ( $rs_row['job_item_id'] == TTUUID::getNotExistID() && ( $row['job_item_id'] == TTUUID::getZeroID() || $rs_row['default_job_item_id'] == $row['default_job_item_id'] ) ) || ( $row['job_item_id'] == TTUUID::getNotExistID() && $rs_row['job_item_id'] == $row['default_job_item_id'] ) )
|
|
) {
|
|
//Debug::Text( ' Committed Shift overrides Recurring Shift: ' . $row['id'] . '[' . $row['layer_order'] . '] ( Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ') That overlaps recurring shift: ' . $rs_row['id'] . ' ( Start: ' . TTDate::getDate( 'DATE+TIME', $rs_row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $rs_row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
$recurring_schedules[$row['user_id']][$row_iso_date_stamp][$rs_key] = $row;
|
|
continue 3;
|
|
}
|
|
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//No override found, because "continue 2" didn't trigger above, keep this shift.
|
|
//Debug::Text( ' Committed Shift DOES NOT override Recurring Shift: ' . $row['id'] . '['. $row['layer_order'] .'] ( Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
$recurring_schedules[$row['user_id']][$row_iso_date_stamp][] = $row;
|
|
} else if ( $row['layer_order'] == 8 ) { //OPEN recurring shifts
|
|
foreach( $recurring_schedules as $rs_user_id => $rs_user_date_rows ) {
|
|
if ( isset($rs_user_date_rows[$row_iso_date_stamp]) ) {
|
|
foreach ( $rs_user_date_rows[$row_iso_date_stamp] as $rs_key => $rs_row ) {
|
|
//All shifts overlapping OPEN shifts must match exactly
|
|
if ( !isset( $rs_row['override'] )
|
|
&& $row['user_id'] == TTUUID::getZeroID()
|
|
&& $row['start_time'] == $rs_row['start_time'] && $row['end_time'] == $rs_row['end_time']
|
|
&& ( $row['status_id'] == $rs_row['status_id'] && ( $row['status_id'] == 10 || ( $row['status_id'] == 20 && $row['absence_policy_id'] == $rs_row['absence_policy_id'] ) ) ) //Absence shifts can only fill OPEN shifts if the absence policy matches so customers can use OPEN shifts for On-Call Absence scheduling. In most cases though, if a working shift that is filling an open shift changes to absence, the open shift should be unfilled.
|
|
&& ( ( $row['branch_id'] != TTUUID::getNotExistID() && $row['branch_id'] == $rs_row['branch_id'] ) || ( $row['branch_id'] == TTUUID::getNotExistID() && ( $row['branch_id'] == $rs_row['branch_id'] || $rs_row['branch_id'] == TTUUID::getZeroID() || ( $rs_row['branch_id'] == TTUUID::getNotExistID() && ( $rs_row['default_branch_id'] == TTUUID::getZeroID() ) ) || $rs_row['branch_id'] == $rs_row['default_branch_id'] ) ) || ( $rs_row['branch_id'] == TTUUID::getNotExistID() && $row['branch_id'] == $rs_row['default_branch_id'] ) )
|
|
&& ( ( $row['department_id'] != TTUUID::getNotExistID() && $row['department_id'] == $rs_row['department_id'] ) || ( $row['department_id'] == TTUUID::getNotExistID() && ( $row['department_id'] == $rs_row['department_id'] || $rs_row['department_id'] == TTUUID::getZeroID() || ( $rs_row['department_id'] == TTUUID::getNotExistID() && ( $rs_row['default_department_id'] == TTUUID::getZeroID() ) ) || $rs_row['department_id'] == $rs_row['default_department_id'] ) ) || ( $rs_row['department_id'] == TTUUID::getNotExistID() && $row['department_id'] == $rs_row['default_department_id'] ) )
|
|
&& ( ( $row['job_id'] != TTUUID::getNotExistID() && $row['job_id'] == $rs_row['job_id'] ) || ( $row['job_id'] == TTUUID::getNotExistID() && ( $row['job_id'] == $rs_row['job_id'] || $rs_row['job_id'] == TTUUID::getZeroID() || ( $rs_row['job_id'] == TTUUID::getNotExistID() && ( $rs_row['default_job_id'] == TTUUID::getZeroID() ) ) || $rs_row['job_id'] == $rs_row['default_job_id'] ) ) || ( $rs_row['job_id'] == TTUUID::getNotExistID() && $row['job_id'] == $rs_row['default_job_id'] ) )
|
|
&& ( ( $row['job_item_id'] != TTUUID::getNotExistID() && $row['job_item_id'] == $rs_row['job_item_id'] ) || ( $row['job_item_id'] == TTUUID::getNotExistID() && ( $row['job_item_id'] == $rs_row['job_item_id'] || $rs_row['job_item_id'] == TTUUID::getZeroID() || ( $rs_row['job_item_id'] == TTUUID::getNotExistID() && ( $rs_row['default_job_item_id'] == TTUUID::getZeroID() ) ) || $rs_row['job_item_id'] == $rs_row['default_job_item_id'] ) ) || ( $rs_row['job_item_id'] == TTUUID::getNotExistID() && $row['job_item_id'] == $rs_row['default_job_item_id'] ) )
|
|
) {
|
|
//Debug::Text( ' Recurring OR Committed Shift overrides OPEN shift: ' . $row['id'] . '[' . $row['layer_order'] . '] ( Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ') That overlaps recurring shift: ' . $rs_row['id'] . ' ( Start: ' . TTDate::getDate( 'DATE+TIME', $rs_row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $rs_row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
unset( $recurring_schedules[$rs_user_id][$row_iso_date_stamp][$rs_key] );
|
|
$retarr[] = $row['id']; //Exclude $row in this case.
|
|
continue 3; //Move to next $row in outer loop
|
|
}
|
|
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//No override found, because "continue 3" didn't trigger above, keep this shift.
|
|
//Debug::Text( ' No override found, keep OPEN recurring Shift: ' . $row['id'] . '['. $row['layer_order'] .'] ( Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
$recurring_schedules[$row['user_id']][$row_iso_date_stamp][] = array_merge( $row, [ 'override' => 1 ] );
|
|
} else if ( $row['layer_order'] == 9 ) { //OPEN committed shifts
|
|
foreach( $recurring_schedules as $rs_user_id => $rs_user_date_rows ) {
|
|
if ( isset($rs_user_date_rows[$row_iso_date_stamp]) ) {
|
|
foreach ( $rs_user_date_rows[$row_iso_date_stamp] as $rs_key => $rs_row ) {
|
|
//All shifts overlapping OPEN shifts must match exactly
|
|
if ( $row['user_id'] == $rs_row['user_id']
|
|
&& $row['start_time'] == $rs_row['start_time'] && $row['end_time'] == $rs_row['end_time']
|
|
&& ( $row['branch_id'] == $rs_row['branch_id'] || ( $rs_row['branch_id'] == TTUUID::getNotExistID() && $row['branch_id'] == TTUUID::getZeroID() ) )
|
|
&& ( $row['department_id'] == $rs_row['department_id'] || ( $rs_row['department_id'] == TTUUID::getNotExistID() && $row['department_id'] == TTUUID::getZeroID() ) )
|
|
&& ( $row['job_id'] == $rs_row['job_id'] || ( $rs_row['job_id'] == TTUUID::getNotExistID() && $row['job_id'] == TTUUID::getZeroID() ) )
|
|
&& ( $row['job_item_id'] == $rs_row['job_item_id'] || ( $rs_row['job_item_id'] == TTUUID::getNotExistID() && $row['job_item_id'] == TTUUID::getZeroID() ) )
|
|
) {
|
|
//Debug::Text( ' OPEN Committed Shift overrides OPEN shift: ' . $row['id'] . '[' . $row['layer_order'] . '] ( Start: ' . TTDate::getDate( 'DATE+TIME', $row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $row['end_time'] ) . ') That overlaps recurring shift: ' . $rs_row['id'] . ' ( Start: ' . TTDate::getDate( 'DATE+TIME', $rs_row['start_time'] ) . ' End: ' . TTDate::getDate( 'DATE+TIME', $rs_row['end_time'] ) . ')', __FILE__, __LINE__, __METHOD__, 10 );
|
|
unset( $recurring_schedules[$rs_user_id][$row_iso_date_stamp][$rs_key] );
|
|
$retarr[] = $rs_row['id']; //Exclude $rs_row (recurring) in this case.
|
|
continue 3;
|
|
}
|
|
|
|
$i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug::Text( 'Total Loops: ' . $i, __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
$retarr = array_unique( $retarr );
|
|
unset($recurring_schedules, $rs_user_rows, $row_row, $rs_user_id, $row);
|
|
}
|
|
unset($rows);
|
|
|
|
if ( isset( $retarr ) ) {
|
|
//Debug::Arr($retarr, 'Excluded Recurring OPEN shifts: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
Debug::Text( 'Excluded Recurring OPEN shifts: ' . count( $retarr ), __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return $retarr;
|
|
}
|
|
|
|
Debug::Text( 'NO Excluded Recurring OPEN shifts...', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $company_id UUID
|
|
* @param $filter_data
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getSearchByCompanyIdAndArrayCriteria( $company_id, $filter_data, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
$exclude_recurring_schedule_ids = $this->getOverriddenOpenShiftRecurringSchedules( $company_id, $filter_data );
|
|
|
|
if ( !is_array( $order ) ) {
|
|
//Use Filter Data ordering if its set.
|
|
if ( isset( $filter_data['sort_column'] ) && $filter_data['sort_order'] ) {
|
|
$order = [ Misc::trimSortPrefix( $filter_data['sort_column'] ) => $filter_data['sort_order'] ];
|
|
}
|
|
}
|
|
|
|
$additional_order_fields = [ 'pay_period_id', 'user_id', 'last_name' ];
|
|
|
|
$sort_column_aliases = [
|
|
'pay_period' => 'udf.pay_period',
|
|
'user_id' => 'udf.user_id',
|
|
'status_id' => 'a.status_id',
|
|
'last_name' => 'uf.last_name',
|
|
'first_name' => 'uf.first_name',
|
|
];
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { //Needed for unit tests to pass when doing pure edition tests.
|
|
$additional_order_fields = array_merge( [ 'jf.name', 'jif.name' ], $additional_order_fields );
|
|
|
|
$sort_column_aliases = array_merge( [
|
|
'job' => 'jf.name',
|
|
'job_item' => 'jif.name',
|
|
], $sort_column_aliases );
|
|
}
|
|
|
|
$order = $this->getColumnsFromAliases( $order, $sort_column_aliases );
|
|
if ( $order == null ) {
|
|
//$order = array( 'udf.pay_period_id' => 'asc', 'udf.user_id' => 'asc', 'a.start_time' => 'asc' );
|
|
//Sort by start_time first, then user, so when only showing 1st page, it has all employees working on the first day, not just some of the employees for multiple days.
|
|
$order = [ 'a.user_id' => '= \'' . TTUUID::getZeroID() . '\' desc', 'a.start_time' => 'asc', 'uf.last_name' => 'asc', 'a.recurring_schedule_id' => 'asc', 'a.id' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
//Debug::Arr($order, 'Order Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
//Debug::Arr($filter_data, 'Filter Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
if ( isset( $filter_data['exclude_user_ids'] ) ) {
|
|
$filter_data['exclude_id'] = $filter_data['exclude_user_ids'];
|
|
}
|
|
if ( isset( $filter_data['include_user_ids'] ) ) {
|
|
$filter_data['id'] = $filter_data['include_user_ids'];
|
|
}
|
|
if ( isset( $filter_data['include_user_id'] ) ) {
|
|
$filter_data['id'] = $filter_data['include_user_id'];
|
|
}
|
|
|
|
if ( isset( $filter_data['pay_period_ids'] ) ) {
|
|
$filter_data['pay_period_id'] = $filter_data['pay_period_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['user_status_ids'] ) ) {
|
|
$filter_data['user_status_id'] = $filter_data['user_status_ids'];
|
|
}
|
|
if ( isset( $filter_data['user_title_ids'] ) ) {
|
|
$filter_data['title_id'] = $filter_data['user_title_ids'];
|
|
}
|
|
if ( isset( $filter_data['group_ids'] ) ) {
|
|
$filter_data['group_id'] = $filter_data['group_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_branch_ids'] ) ) {
|
|
$filter_data['default_branch_id'] = $filter_data['default_branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_department_ids'] ) ) {
|
|
$filter_data['default_department_id'] = $filter_data['default_department_ids'];
|
|
}
|
|
if ( isset( $filter_data['status_ids'] ) ) {
|
|
$filter_data['status_id'] = $filter_data['status_ids'];
|
|
}
|
|
if ( isset( $filter_data['branch_ids'] ) ) {
|
|
$filter_data['schedule_branch_id'] = $filter_data['branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['department_ids'] ) ) {
|
|
$filter_data['schedule_department_id'] = $filter_data['department_ids'];
|
|
}
|
|
if ( isset( $filter_data['schedule_branch_ids'] ) ) {
|
|
$filter_data['schedule_branch_id'] = $filter_data['schedule_branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['schedule_department_ids'] ) ) {
|
|
$filter_data['schedule_department_id'] = $filter_data['schedule_department_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['exclude_job_ids'] ) ) {
|
|
$filter_data['exclude_id'] = $filter_data['exclude_job_ids'];
|
|
}
|
|
if ( isset( $filter_data['include_job_ids'] ) ) {
|
|
$filter_data['include_job_id'] = $filter_data['include_job_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_group_ids'] ) ) {
|
|
$filter_data['job_group_id'] = $filter_data['job_group_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_item_ids'] ) ) {
|
|
$filter_data['job_item_id'] = $filter_data['job_item_ids'];
|
|
}
|
|
|
|
$uf = new UserFactory();
|
|
$uwf = new UserWageFactory();
|
|
$apf = new AbsencePolicyFactory();
|
|
$bf = new BranchFactory();
|
|
$df = new DepartmentFactory();
|
|
$ugf = new UserGroupFactory();
|
|
$utf = new UserTitleFactory();
|
|
$sf = new ScheduleFactory();
|
|
$rsf = new RecurringScheduleFactory();
|
|
$rscf = new RecurringScheduleControlFactory();
|
|
|
|
//When filtering by pay_period_id (ie: this pay period), if their are recurring scheduled shifts in the future but before the end of this pay period,
|
|
// they won't be displayed on the report because recurring_schedule records are not assigned to pay_period_id, since they are mostly in the future.
|
|
// therefore we need to join to the pay_period table to figure out which pay_period the future dates belong too.
|
|
// This isn't perfect, and will really only be useful for one pay period in the future, and doesn't handle PP schedule changes very well, but it should suffice for now.
|
|
$ppsuf = new PayPeriodScheduleUserFactory();
|
|
$ppsf = new PayPeriodScheduleFactory();
|
|
$ppf = new PayPeriodFactory();
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$jf = new JobFactory();
|
|
$jgf = new JobGroupFactory();
|
|
$jif = new JobItemFactory();
|
|
$jigf = new JobItemGroupFactory();
|
|
$ptf = new PunchTagFactory();
|
|
$ptlf = new PunchTagGroupFactory();
|
|
}
|
|
|
|
$ph = [];
|
|
|
|
$query = '
|
|
select
|
|
a.id as id,
|
|
a.id as schedule_id,
|
|
a.recurring_schedule_id as recurring_schedule_id,
|
|
a.replaced_id as replaced_id,
|
|
a.status_id as status_id,
|
|
a.start_time as start_time,
|
|
a.end_time as end_time,
|
|
|
|
a.branch_id as branch_id,
|
|
bfb.name as branch,
|
|
a.department_id as department_id,
|
|
dfb.name as department,
|
|
a.job_id as job_id,
|
|
a.job_item_id as job_item_id,
|
|
a.punch_tag_id as punch_tag_id, ';
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ' ( SELECT STRING_AGG( tmp_pt.name, \',\' ) FROM ' . $ptf->getTable() . ' AS tmp_pt where tmp_pt.company_id = \'' . TTUUID::castUUID( $company_id ) . '\' AND tmp_pt.id IN ( SELECT ( jsonb_array_elements( a.punch_tag_id )->>0 )::uuid ) AND tmp_pt.deleted = 0 ) AS punch_tag, ';
|
|
} else {
|
|
$query .= ' NULL AS punch_tag, ';
|
|
}
|
|
|
|
$query .= '
|
|
a.total_time as total_time,
|
|
a.schedule_policy_id as schedule_policy_id,
|
|
a.absence_policy_id as absence_policy_id,
|
|
apf.name as absence_policy,
|
|
apf.type_id as absence_policy_type_id,
|
|
|
|
a.note as note,
|
|
|
|
a.created_date as created_date,
|
|
a.updated_date as updated_date,
|
|
|
|
bf.name as default_branch,
|
|
df.name as default_department,
|
|
ugf.name as "group",
|
|
utf.name as title,
|
|
|
|
a.user_id as user_id,
|
|
a.date_stamp as date_stamp,
|
|
a.pay_period_id as pay_period_id,
|
|
ppf.start_date as pay_period_start_date,
|
|
ppf.end_date as pay_period_end_date,
|
|
ppf.transaction_date as pay_period_transaction_date,
|
|
|
|
uf.first_name as first_name,
|
|
uf.last_name as last_name,
|
|
uf.default_branch_id as default_branch_id,
|
|
uf.default_department_id as default_department_id,
|
|
uf.title_id as title_id,
|
|
uf.group_id as group_id,
|
|
uf.created_by as user_created_by,
|
|
|
|
uwf.id as user_wage_id,
|
|
uwf.hourly_rate as user_wage_hourly_rate,
|
|
uwf.labor_burden_percent as user_labor_burden_percent,
|
|
uwf.effective_date as user_wage_effective_date, ';
|
|
|
|
$query .= Permission::getPermissionIsChildIsOwnerSQL( ( isset( $filter_data['permission_current_user_id'] ) ) ? $filter_data['permission_current_user_id'] : TTUUID::getZeroID(), 'a.user_id', false, ( isset( $filter_data['permission_is_id'] ) && $filter_data['permission_is_id'] == TTUUID::getZeroID() ) ? $filter_data['permission_is_id'] : null );
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ',
|
|
jfb.name as default_job,
|
|
jifb.name as default_job_item,
|
|
|
|
jf.name as job,
|
|
jf.description as job_description,
|
|
jf.status_id as job_status_id,
|
|
jf.manual_id as job_manual_id,
|
|
jf.branch_id as job_branch_id,
|
|
jbf.name as job_branch,
|
|
jf.department_id as job_department_id,
|
|
jdf.name as job_department,
|
|
jf.group_id as job_group_id,
|
|
jgf.name as job_group,
|
|
jf.custom_field as job_custom_field,
|
|
jf.address1 as job_address1,
|
|
jf.address2 as job_address2,
|
|
jf.city as job_city,
|
|
jf.country as job_country,
|
|
jf.province as job_province,
|
|
jf.postal_code as job_postal_code,
|
|
jf.longitude as job_longitude,
|
|
jf.latitude as job_latitude,
|
|
jf.location_note as job_location_note,
|
|
jif.name as job_item,
|
|
jif.description as job_item_description,
|
|
jif.manual_id as job_item_manual_id,
|
|
jif.group_id as job_item_group_id,
|
|
jigf.name as job_item_group
|
|
';
|
|
}
|
|
|
|
$query .= '
|
|
FROM (
|
|
(
|
|
SELECT
|
|
sf.id as id,
|
|
sf.id as schedule_id,
|
|
sf.replaced_id as replaced_id,
|
|
NULL as recurring_schedule_id,
|
|
sf.company_id as company_id,
|
|
|
|
sf.user_id as user_id,
|
|
sf.recurring_schedule_template_control_id,
|
|
sf.date_stamp as date_stamp,
|
|
sf.pay_period_id as pay_period_id,
|
|
|
|
sf.status_id as status_id,
|
|
sf.start_time as start_time,
|
|
sf.end_time as end_time,
|
|
|
|
sf.branch_id as branch_id,
|
|
sf.department_id as department_id,
|
|
sf.job_id as job_id,
|
|
sf.job_item_id as job_item_id,
|
|
sf.punch_tag_id as punch_tag_id,
|
|
sf.total_time as total_time,
|
|
sf.schedule_policy_id as schedule_policy_id,
|
|
sf.absence_policy_id as absence_policy_id,
|
|
|
|
sf.note as note,
|
|
sf.custom_field as custom_field,
|
|
|
|
sf.created_date as created_date,
|
|
sf.updated_date as updated_date,
|
|
sf.deleted as deleted
|
|
FROM ' . $sf->getTable() . ' as sf
|
|
LEFT JOIN ' . $sf->getTable() . ' as sf_b ON ( sf.id = sf_b.replaced_id AND sf_b.deleted = 0 )
|
|
WHERE sf.company_id = \'' . TTUUID::castUUID( $company_id ) . '\'
|
|
';
|
|
|
|
if ( isset( $filter_data['start_date'] ) && !is_array( $filter_data['start_date'] ) && trim( $filter_data['start_date'] ) != '' ) {
|
|
$ph[] = $this->db->BindDate( ( (int)TTDate::parseDateTime( $filter_data['start_date'] ) - 86400 ) );
|
|
$query .= ' AND sf.date_stamp >= ?';
|
|
}
|
|
if ( isset( $filter_data['end_date'] ) && !is_array( $filter_data['end_date'] ) && trim( $filter_data['end_date'] ) != '' ) {
|
|
$ph[] = $this->db->BindDate( ( (int)TTDate::parseDateTime( $filter_data['end_date'] ) + 86400 ) );
|
|
$query .= ' AND sf.date_stamp <= ?';
|
|
}
|
|
|
|
$query .= '
|
|
|
|
AND sf_b.replaced_id IS NULL
|
|
AND sf.deleted = 0
|
|
)
|
|
UNION ALL
|
|
(
|
|
SELECT
|
|
NULL as id,
|
|
rsf.id as schedule_id,
|
|
NULL as replaced_id,
|
|
rsf.id as recurring_schedule_id,
|
|
rsf.company_id as company_id,
|
|
|
|
rsf.user_id as user_id,
|
|
rsf.recurring_schedule_template_control_id,
|
|
rsf.date_stamp as date_stamp,
|
|
ppf.id as pay_period_id,
|
|
|
|
rsf.status_id as status_id,
|
|
rsf.start_time as start_time,
|
|
rsf.end_time as end_time,
|
|
|
|
CASE WHEN rsf.branch_id = \'' . TTUUID::getNotExistID() . '\' THEN uf_b.default_branch_id ELSE rsf.branch_id END as branch_id,
|
|
CASE WHEN rsf.department_id = \'' . TTUUID::getNotExistID() . '\' THEN uf_b.default_department_id ELSE rsf.department_id END as department_id,
|
|
CASE WHEN rsf.job_id = \'' . TTUUID::getNotExistID() . '\' THEN uf_b.default_job_id ELSE rsf.job_id END as job_id,
|
|
CASE WHEN rsf.job_item_id = \'' . TTUUID::getNotExistID() . '\' THEN uf_b.default_job_item_id ELSE rsf.job_item_id END as job_item_id,
|
|
CASE WHEN rsf.punch_tag_id = \'["' . TTUUID::getNotExistID() . '"]\' THEN uf_b.default_punch_tag_id ELSE rsf.punch_tag_id END as punch_tag_id,
|
|
|
|
rsf.total_time as total_time,
|
|
rsf.schedule_policy_id as schedule_policy_id,
|
|
rsf.absence_policy_id as absence_policy_id,
|
|
|
|
rsf.note as note,
|
|
NULL as custom_field,
|
|
|
|
rsf.created_date as created_date,
|
|
rsf.updated_date as updated_date,
|
|
rsf.deleted as deleted
|
|
FROM ' . $rsf->getTable() . ' as rsf
|
|
LEFT JOIN ' . $rscf->getTable() . ' as rscf ON rsf.recurring_schedule_control_id = rscf.id
|
|
LEFT JOIN ' . $uf->getTable() . ' as uf_b ON rsf.user_id = uf_b.id
|
|
LEFT JOIN ' . $ppsuf->getTable() . ' as ppsuf ON ( rsf.user_id = ppsuf.user_id )
|
|
LEFT JOIN ' . $ppsf->getTable() . ' as ppsf ON ( ppsuf.pay_period_schedule_id = ppsf.id AND ppsf.deleted = 0 )
|
|
LEFT JOIN ' . $ppf->getTable() . ' as ppf ON ( ppf.pay_period_schedule_id = ppsuf.pay_period_schedule_id AND rsf.date_stamp >= ppf.start_date AND rsf.date_stamp <= ppf.end_date AND ppf.deleted = 0 )
|
|
LEFT JOIN schedule as sf_b ON (
|
|
( sf_b.user_id != \'' . TTUUID::getZeroID() . '\' AND sf_b.user_id = rsf.user_id ) ';
|
|
|
|
if ( isset( $filter_data['start_date'] ) && !is_array( $filter_data['start_date'] ) && trim( (string)$filter_data['start_date'] ) != '' ) {
|
|
$ph[] = $this->db->BindDate( ( (int)TTDate::parseDateTime( $filter_data['start_date'] ) - 86400 ) );
|
|
$query .= ' AND sf_b.date_stamp >= ?';
|
|
}
|
|
if ( isset( $filter_data['end_date'] ) && !is_array( $filter_data['end_date'] ) && trim( (string)$filter_data['end_date'] ) != '' ) {
|
|
$ph[] = $this->db->BindDate( ( (int)TTDate::parseDateTime( $filter_data['end_date'] ) + 86400 ) );
|
|
$query .= ' AND sf_b.date_stamp <= ?';
|
|
}
|
|
|
|
$query .= ' AND
|
|
(
|
|
sf_b.start_time >= rsf.start_time AND sf_b.end_time <= rsf.end_time
|
|
OR
|
|
sf_b.start_time >= rsf.start_time AND sf_b.start_time < rsf.end_time
|
|
OR
|
|
sf_b.end_time > rsf.start_time AND sf_b.end_time <= rsf.end_time
|
|
OR
|
|
sf_b.start_time <= rsf.start_time AND sf_b.end_time >= rsf.end_time
|
|
OR
|
|
sf_b.start_time = rsf.start_time AND sf_b.end_time = rsf.end_time
|
|
)
|
|
AND sf_b.deleted = 0
|
|
)
|
|
WHERE sf_b.id is NULL
|
|
AND rsf.company_id = \'' . TTUUID::castUUID( $company_id ) . '\'
|
|
AND ( uf_b.hire_date IS NULL OR uf_b.hire_date <= rsf.date_stamp )
|
|
AND ( uf_b.termination_date IS NULL OR uf_b.termination_date >= rsf.date_stamp )';
|
|
|
|
if ( $exclude_recurring_schedule_ids != false ) {
|
|
$query .= ' AND rsf.id NOT IN ( ' . $this->getListSQL( $exclude_recurring_schedule_ids ) . ' ) ';
|
|
}
|
|
|
|
$query .= '
|
|
AND ( rsf.deleted = 0 AND rscf.deleted = 0 AND ( ppsf.deleted IS NULL OR ppsf.deleted = 0 ) AND ( uf_b.deleted IS NULL OR uf_b.deleted = 0 ) )
|
|
)
|
|
) as a
|
|
|
|
LEFT JOIN ' . $uf->getTable() . ' as uf ON ( a.user_id = uf.id AND uf.deleted = 0 )
|
|
LEFT JOIN ' . $bf->getTable() . ' as bf ON ( uf.default_branch_id = bf.id AND bf.deleted = 0)
|
|
LEFT JOIN ' . $bf->getTable() . ' as bfb ON ( a.branch_id = bfb.id AND bfb.deleted = 0)
|
|
LEFT JOIN ' . $df->getTable() . ' as df ON ( uf.default_department_id = df.id AND df.deleted = 0)
|
|
LEFT JOIN ' . $df->getTable() . ' as dfb ON ( a.department_id = dfb.id AND dfb.deleted = 0)
|
|
LEFT JOIN ' . $ugf->getTable() . ' as ugf ON ( uf.group_id = ugf.id AND ugf.deleted = 0 )
|
|
LEFT JOIN ' . $utf->getTable() . ' as utf ON ( uf.title_id = utf.id AND utf.deleted = 0 )
|
|
LEFT JOIN ' . $apf->getTable() . ' as apf ON ( a.absence_policy_id = apf.id )
|
|
LEFT JOIN ' . $ppf->getTable() . ' as ppf ON ( a.pay_period_id = ppf.id AND ppf.deleted = 0 )
|
|
LEFT JOIN ' . $uwf->getTable() . ' as uwf ON uwf.id = (select z.id
|
|
from ' . $uwf->getTable() . ' as z
|
|
where z.user_id = a.user_id
|
|
and z.effective_date <= a.date_stamp
|
|
and z.deleted = 0
|
|
order by z.effective_date desc limit 1)
|
|
';
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= '
|
|
LEFT JOIN ' . $jf->getTable() . ' as jfb ON ( uf.default_job_id = jfb.id AND jfb.deleted = 0 )
|
|
LEFT JOIN ' . $jif->getTable() . ' as jifb ON ( uf.default_job_item_id = jifb.id AND jifb.deleted = 0 )
|
|
|
|
LEFT JOIN ' . $jf->getTable() . ' as jf ON ( a.job_id = jf.id AND jf.deleted = 0 )
|
|
LEFT JOIN ' . $jif->getTable() . ' as jif ON ( a.job_item_id = jif.id AND jif.deleted = 0 )
|
|
LEFT JOIN ' . $bf->getTable() . ' as jbf ON ( jf.branch_id = jbf.id AND jbf.deleted = 0 )
|
|
LEFT JOIN ' . $df->getTable() . ' as jdf ON ( jf.department_id = jdf.id AND jdf.deleted = 0 )
|
|
LEFT JOIN ' . $jgf->getTable() . ' as jgf ON ( jf.group_id = jgf.id AND jgf.deleted = 0 )
|
|
LEFT JOIN ' . $jigf->getTable() . ' as jigf ON ( jif.group_id = jigf.id AND jigf.deleted = 0 )
|
|
';
|
|
}
|
|
|
|
$query .= Permission::getPermissionHierarchySQL( $company_id, ( isset( $filter_data['permission_current_user_id'] ) ) ? $filter_data['permission_current_user_id'] : 0, 'a.user_id' );
|
|
|
|
$query .= ' WHERE ( a.company_id = \'' . TTUUID::castUUID( $company_id ) . '\' )';
|
|
|
|
$query .= Permission::getPermissionIsChildIsOwnerFilterSQL( $filter_data, 'a.user_id' );
|
|
$query .= ( isset( $filter_data['permission_children_ids'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['permission_children_ids'], 'uuid_list', $ph ) : null;
|
|
//Make sure we filter on user_date.user_id column, to handle OPEN shifts.
|
|
$query .= ( isset( $filter_data['id'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_id'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['exclude_id'], 'not_uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['recurring_schedule_id'] ) ) ? $this->getWhereClauseSQL( 'a.recurring_schedule_id', $filter_data['recurring_schedule_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_id'] ) ) ? $this->getWhereClauseSQL( 'a.schedule_id', $filter_data['schedule_id'], 'uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['user_status_id'] ) ) ? $this->getWhereClauseSQL( 'uf.status_id', $filter_data['user_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['group_id'] ) ) ? $this->getWhereClauseSQL( 'uf.group_id', $filter_data['group_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['title_id'] ) ) ? $this->getWhereClauseSQL( 'uf.title_id', $filter_data['title_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['first_name'] ) ) ? $this->getWhereClauseSQL( 'uf.first_name', $filter_data['first_name'], 'text_metaphone', $ph ) : null;
|
|
$query .= ( isset( $filter_data['last_name'] ) ) ? $this->getWhereClauseSQL( 'uf.last_name', $filter_data['last_name'], 'text_metaphone', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['default_branch_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_branch_id', $filter_data['default_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_department_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_department_id', $filter_data['default_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_job_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_job_id', $filter_data['default_job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_job_item_id', $filter_data['default_job_item_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_punch_tag_id'] ) ) ? $this->getWhereClauseSQL( 'uf.default_punch_tag_id', $filter_data['default_punch_tag_id'], 'jsonb_uuid_array', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['punch_branch_id'] ) ) ? $this->getWhereClauseSQL( 'a.branch_id', $filter_data['punch_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['punch_department_id'] ) ) ? $this->getWhereClauseSQL( 'a.department_id', $filter_data['punch_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['punch_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['punch_job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['punch_job_item_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_item_id', $filter_data['punch_job_item_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['punch_tag_id'] ) ) ? $this->getWhereClauseSQL( 'a.punch_tag_id', $filter_data['punch_tag_id'], 'jsonb_uuid_array', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['recurring_schedule_template_control_id'] ) ) ? $this->getWhereClauseSQL( 'a.recurring_schedule_template_control_id', $filter_data['recurring_schedule_template_control_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_branch_id'] ) ) ? $this->getWhereClauseSQL( 'a.branch_id', $filter_data['schedule_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_department_id'] ) ) ? $this->getWhereClauseSQL( 'a.department_id', $filter_data['schedule_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['status_id'] ) ) ? $this->getWhereClauseSQL( 'a.status_id', $filter_data['status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.schedule_policy_id', $filter_data['schedule_policy_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['absence_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.absence_policy_id', $filter_data['absence_policy_id'], 'uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['pay_period_id'] ) ) ? $this->getWhereClauseSQL( 'a.pay_period_id', $filter_data['pay_period_id'], 'uuid_list', $ph ) : null;
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ( isset( $filter_data['job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_status_id'] ) ) ? $this->getWhereClauseSQL( 'a.status_id', $filter_data['job_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['include_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['include_job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['exclude_job_id'], 'not_uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_group_id'] ) ) ? $this->getWhereClauseSQL( 'jf.group_id', $filter_data['job_group_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_item_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_item_id', $filter_data['job_item_id'], 'uuid_list', $ph ) : null;
|
|
}
|
|
|
|
$query .= $this->getCustomFieldWhereSQL( $company_id, 'a.custom_field', $filter_data, $ph );
|
|
|
|
$query .= ( isset( $filter_data['date_stamp'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', $filter_data['date_stamp'], 'date_range_datestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['start_date'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', $filter_data['start_date'], 'start_datestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_date'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', $filter_data['end_date'], 'end_datestamp', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['start_time'] ) ) ? $this->getWhereClauseSQL( 'a.start_time', $filter_data['start_time'], 'start_timestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_time'] ) ) ? $this->getWhereClauseSQL( 'a.end_time', $filter_data['end_time'], 'end_timestamp', $ph ) : null;
|
|
|
|
$query .= '
|
|
AND ( a.deleted = 0 AND ( uf.deleted IS NULL OR uf.deleted = 0 ) )
|
|
';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict, $additional_order_fields );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page );
|
|
//Debug::Query($query, $ph, __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param string $company_id UUID
|
|
* @param $filter_data
|
|
* @param int $limit Limit the number of records returned
|
|
* @param int $page Page number of records to return for pagination
|
|
* @param array $where Additional SQL WHERE clause in format of array( $column => $filter, ... ). ie: array( 'id' => 1, ... )
|
|
* @param array $order Sort order passed to SQL in format of array( $column => 'asc', 'name' => 'desc', ... ). ie: array( 'id' => 'asc', 'name' => 'desc', ... )
|
|
* @return bool|ScheduleListFactory
|
|
*/
|
|
function getAPISearchByCompanyIdAndArrayCriteria( $company_id, $filter_data, $limit = null, $page = null, $where = null, $order = null ) {
|
|
if ( $company_id == '' ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !is_array( $order ) ) {
|
|
//Use Filter Data ordering if its set.
|
|
if ( isset( $filter_data['sort_column'] ) && $filter_data['sort_order'] ) {
|
|
$order = [ Misc::trimSortPrefix( $filter_data['sort_column'] ) => $filter_data['sort_order'] ];
|
|
}
|
|
}
|
|
|
|
$additional_order_fields = [ 'schedule_policy_id', 'schedule_policy', 'absence_policy', 'first_name', 'last_name', 'user_status_id', 'group_id', 'group', 'title_id', 'title', 'default_branch_id', 'default_branch', 'default_department_id', 'default_department', 'total_time', 'date_stamp', 'pay_period_id', 'j.name', 'k.name' ];
|
|
|
|
$sort_column_aliases = [
|
|
'status' => 'status_id',
|
|
'first_name' => 'd.first_name',
|
|
'last_name' => 'd.last_name',
|
|
'user_status' => 'user_status_id',
|
|
'branch' => 'j.name',
|
|
'department' => 'k.name',
|
|
'updated_date' => 'a.updated_date',
|
|
'created_date' => 'a.created_date',
|
|
];
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) { //Needed for unit tests to pass when doing pure edition tests.
|
|
$additional_order_fields = array_merge( [ 'w.name', 'x.name' ], $additional_order_fields );
|
|
|
|
$sort_column_aliases = array_merge( [
|
|
'job' => 'w.name',
|
|
'job_item' => 'x.name',
|
|
], $sort_column_aliases );
|
|
}
|
|
|
|
$order = $this->getColumnsFromAliases( $order, $sort_column_aliases );
|
|
if ( $order == null ) {
|
|
$order = [ 'a.start_time' => 'desc', 'd.last_name' => 'asc', 'd.first_name' => 'asc', 'a.user_id' => 'asc' ];
|
|
$strict = false;
|
|
} else {
|
|
$strict = true;
|
|
}
|
|
//Debug::Arr($order, 'Order Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
//Debug::Arr($filter_data, 'Filter Data:', __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
//if ( isset($filter_data['exclude_user_ids']) ) {
|
|
// $filter_data['exclude_id'] = $filter_data['exclude_user_ids'];
|
|
//}
|
|
if ( isset( $filter_data['exclude_user_ids'] ) ) {
|
|
$filter_data['exclude_user_id'] = $filter_data['exclude_user_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['include_user_ids'] ) ) {
|
|
$filter_data['user_id'] = $filter_data['include_user_ids'];
|
|
}
|
|
if ( isset( $filter_data['user_status_ids'] ) ) {
|
|
$filter_data['user_status_id'] = $filter_data['user_status_ids'];
|
|
}
|
|
if ( isset( $filter_data['user_title_ids'] ) ) {
|
|
$filter_data['title_id'] = $filter_data['user_title_ids'];
|
|
}
|
|
if ( isset( $filter_data['group_ids'] ) ) {
|
|
$filter_data['group_id'] = $filter_data['group_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_branch_ids'] ) ) {
|
|
$filter_data['default_branch_id'] = $filter_data['default_branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['default_department_ids'] ) ) {
|
|
$filter_data['default_department_id'] = $filter_data['default_department_ids'];
|
|
}
|
|
if ( isset( $filter_data['branch_ids'] ) ) {
|
|
$filter_data['branch_id'] = $filter_data['branch_ids'];
|
|
}
|
|
if ( isset( $filter_data['department_ids'] ) ) {
|
|
$filter_data['department_id'] = $filter_data['department_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['include_job_ids'] ) ) {
|
|
$filter_data['include_job_id'] = $filter_data['include_job_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_group_ids'] ) ) {
|
|
$filter_data['job_group_id'] = $filter_data['job_group_ids'];
|
|
}
|
|
if ( isset( $filter_data['job_item_ids'] ) ) {
|
|
$filter_data['job_item_id'] = $filter_data['job_item_ids'];
|
|
}
|
|
if ( isset( $filter_data['pay_period_ids'] ) ) {
|
|
$filter_data['pay_period_id'] = $filter_data['pay_period_ids'];
|
|
}
|
|
|
|
if ( isset( $filter_data['start_time'] ) ) {
|
|
$filter_data['start_date'] = $filter_data['start_time'];
|
|
}
|
|
if ( isset( $filter_data['end_time'] ) ) {
|
|
$filter_data['end_date'] = $filter_data['end_time'];
|
|
}
|
|
|
|
$spf = new SchedulePolicyFactory();
|
|
$apf = new AbsencePolicyFactory();
|
|
$uf = new UserFactory();
|
|
$bf = new BranchFactory();
|
|
$df = new DepartmentFactory();
|
|
$ugf = new UserGroupFactory();
|
|
$utf = new UserTitleFactory();
|
|
$sf = new ScheduleFactory();
|
|
$uwf = new UserWageFactory();
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$jf = new JobFactory();
|
|
$jif = new JobItemFactory();
|
|
}
|
|
|
|
$ph = [
|
|
'company_id' => TTUUID::castUUID( $company_id ),
|
|
'company_id2' => TTUUID::castUUID( $company_id ),
|
|
];
|
|
|
|
$query = '
|
|
select
|
|
a.id as id,
|
|
a.id as schedule_id,
|
|
a.replaced_id as replaced_id,
|
|
a.status_id as status_id,
|
|
a.start_time as start_time,
|
|
a.end_time as end_time,
|
|
|
|
a.branch_id as branch_id,
|
|
j.name as branch,
|
|
a.department_id as department_id,
|
|
k.name as department,
|
|
a.job_id as job_id,
|
|
a.job_item_id as job_item_id,
|
|
a.punch_tag_id as punch_tag_id,
|
|
a.total_time as total_time,
|
|
a.schedule_policy_id as schedule_policy_id,
|
|
a.absence_policy_id as absence_policy_id,
|
|
a.recurring_schedule_template_control_id as recurring_schedule_template_control_id,
|
|
a.note as note,
|
|
a.custom_field as custom_field,
|
|
|
|
i.name as schedule_policy,
|
|
apf.name as absence_policy,
|
|
|
|
a.user_id as user_id,
|
|
a.date_stamp as date_stamp,
|
|
a.pay_period_id as pay_period_id,
|
|
|
|
d.first_name as first_name,
|
|
d.last_name as last_name,
|
|
d.status_id as user_status_id,
|
|
d.group_id as group_id,
|
|
g.name as "group",
|
|
d.title_id as title_id,
|
|
h.name as title,
|
|
d.default_branch_id as default_branch_id,
|
|
e.name as default_branch,
|
|
d.default_department_id as default_department_id,
|
|
f.name as default_department,
|
|
d.created_by as user_created_by,
|
|
|
|
m.id as user_wage_id,
|
|
m.effective_date as user_wage_effective_date,
|
|
|
|
a.created_date as created_date,
|
|
a.created_by as created_by,
|
|
a.updated_date as updated_date,
|
|
a.updated_by as updated_by,
|
|
|
|
y.first_name as created_by_first_name,
|
|
y.middle_name as created_by_middle_name,
|
|
y.last_name as created_by_last_name,
|
|
z.first_name as updated_by_first_name,
|
|
z.middle_name as updated_by_middle_name,
|
|
z.last_name as updated_by_last_name';
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ',
|
|
w.name as job,
|
|
w.status_id as job_status_id,
|
|
w.manual_id as job_manual_id,
|
|
w.branch_id as job_branch_id,
|
|
w.department_id as job_department_id,
|
|
w.group_id as job_group_id,
|
|
|
|
x.name as job_item,
|
|
x.manual_id as job_item_manual_id,
|
|
x.group_id as job_item_group_id
|
|
';
|
|
}
|
|
|
|
$query .= '
|
|
from ' . $this->getTable() . ' as a
|
|
LEFT JOIN ' . $sf->getTable() . ' as sf ON ( a.id = sf.replaced_id AND sf.deleted = 0 )
|
|
LEFT JOIN ' . $spf->getTable() . ' as i ON a.schedule_policy_id = i.id
|
|
LEFT JOIN ' . $uf->getTable() . ' as d ON ( a.user_id = d.id AND d.deleted = 0 )
|
|
|
|
LEFT JOIN ' . $bf->getTable() . ' as e ON ( d.default_branch_id = e.id AND e.deleted = 0)
|
|
LEFT JOIN ' . $df->getTable() . ' as f ON ( d.default_department_id = f.id AND f.deleted = 0)
|
|
LEFT JOIN ' . $ugf->getTable() . ' as g ON ( d.group_id = g.id AND g.deleted = 0 )
|
|
LEFT JOIN ' . $utf->getTable() . ' as h ON ( d.title_id = h.id AND h.deleted = 0 )
|
|
|
|
LEFT JOIN ' . $bf->getTable() . ' as j ON ( a.branch_id = j.id AND j.deleted = 0)
|
|
LEFT JOIN ' . $df->getTable() . ' as k ON ( a.department_id = k.id AND k.deleted = 0)
|
|
|
|
LEFT JOIN ' . $apf->getTable() . ' as apf ON a.absence_policy_id = apf.id
|
|
|
|
LEFT JOIN ' . $uwf->getTable() . ' as m ON m.id = (select m.id
|
|
from ' . $uwf->getTable() . ' as m
|
|
where m.user_id = a.user_id
|
|
and m.effective_date <= a.date_stamp
|
|
and m.deleted = 0
|
|
order by m.effective_date desc limit 1)
|
|
';
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ' LEFT JOIN ' . $jf->getTable() . ' as w ON a.job_id = w.id';
|
|
$query .= ' LEFT JOIN ' . $jif->getTable() . ' as x ON a.job_item_id = x.id';
|
|
}
|
|
|
|
$query .= '
|
|
LEFT JOIN ' . $uf->getTable() . ' as y ON ( a.created_by = y.id AND y.deleted = 0 )
|
|
LEFT JOIN ' . $uf->getTable() . ' as z ON ( a.updated_by = z.id AND z.deleted = 0 )
|
|
WHERE ( d.company_id = ? OR a.company_id = ? ) AND sf.replaced_id IS NULL ';
|
|
|
|
$query .= ( isset( $filter_data['permission_children_ids'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['permission_children_ids'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['id'] ) ) ? $this->getWhereClauseSQL( 'a.id', $filter_data['id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_id'] ) ) ? $this->getWhereClauseSQL( 'a.id', $filter_data['exclude_id'], 'not_uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['user_id'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['user_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_user_id'] ) ) ? $this->getWhereClauseSQL( 'a.user_id', $filter_data['exclude_user_id'], 'not_uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['user_status_id'] ) ) ? $this->getWhereClauseSQL( 'd.status_id', $filter_data['user_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['group_id'] ) ) ? $this->getWhereClauseSQL( 'd.group_id', $filter_data['group_id'], 'uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['legal_entity_id'] ) ) ? $this->getWhereClauseSQL( 'd.legal_entity_id', $filter_data['legal_entity_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_branch_id'] ) ) ? $this->getWhereClauseSQL( 'd.default_branch_id', $filter_data['default_branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['default_department_id'] ) ) ? $this->getWhereClauseSQL( 'd.default_department_id', $filter_data['default_department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['title_id'] ) ) ? $this->getWhereClauseSQL( 'd.title_id', $filter_data['title_id'], 'uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['branch_id'] ) ) ? $this->getWhereClauseSQL( 'a.branch_id', $filter_data['branch_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['department_id'] ) ) ? $this->getWhereClauseSQL( 'a.department_id', $filter_data['department_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['status_id'] ) ) ? $this->getWhereClauseSQL( 'a.status_id', $filter_data['status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['schedule_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.schedule_policy_id', $filter_data['schedule_policy_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['absence_policy_id'] ) ) ? $this->getWhereClauseSQL( 'a.absence_policy_id', $filter_data['absence_policy_id'], 'uuid_list', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['pay_period_id'] ) ) ? $this->getWhereClauseSQL( 'a.pay_period_id', $filter_data['pay_period_id'], 'uuid_list', $ph ) : null;
|
|
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
$query .= ( isset( $filter_data['job_status_id'] ) ) ? $this->getWhereClauseSQL( 'w.status_id', $filter_data['job_status_id'], 'numeric_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['include_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['include_job_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['exclude_job_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_id', $filter_data['exclude_job_id'], 'not_uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_group_id'] ) ) ? $this->getWhereClauseSQL( 'w.group_id', $filter_data['job_group_id'], 'uuid_list', $ph ) : null;
|
|
$query .= ( isset( $filter_data['job_item_id'] ) ) ? $this->getWhereClauseSQL( 'a.job_item_id', $filter_data['job_item_id'], 'uuid_list', $ph ) : null;
|
|
}
|
|
|
|
$query .= $this->getCustomFieldWhereSQL( $company_id, 'a.custom_field', $filter_data, $ph );
|
|
|
|
$query .= ( isset( $filter_data['date_stamp'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', $filter_data['date_stamp'], 'date_range_datestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['start_date'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', TTDate::parseDateTime( $filter_data['start_date'] ), 'start_datestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_date'] ) ) ? $this->getWhereClauseSQL( 'a.date_stamp', TTDate::parseDateTime( $filter_data['end_date'] ), 'end_datestamp', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['start_time'] ) ) ? $this->getWhereClauseSQL( 'a.start_time', $filter_data['start_time'], 'start_timestamp', $ph ) : null;
|
|
$query .= ( isset( $filter_data['end_time'] ) ) ? $this->getWhereClauseSQL( 'a.end_time', $filter_data['end_time'], 'end_timestamp', $ph ) : null;
|
|
|
|
$query .= ( isset( $filter_data['created_by'] ) ) ? $this->getWhereClauseSQL( [ 'a.created_by', 'y.first_name', 'y.last_name' ], $filter_data['created_by'], 'user_id_or_name', $ph ) : null;
|
|
$query .= ( isset( $filter_data['updated_by'] ) ) ? $this->getWhereClauseSQL( [ 'a.updated_by', 'z.first_name', 'z.last_name' ], $filter_data['updated_by'], 'user_id_or_name', $ph ) : null;
|
|
|
|
$query .= ' AND ( a.deleted = 0 ) ';
|
|
$query .= $this->getWhereSQL( $where );
|
|
$query .= $this->getSortSQL( $order, $strict, $additional_order_fields );
|
|
|
|
$this->rs = $this->ExecuteSQL( $query, $ph, $limit, $page );
|
|
|
|
//Debug::Query( $query, $ph, __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
return $this;
|
|
}
|
|
}
|
|
|
|
?>
|